mirror of
https://github.com/ansible/awx.git
synced 2026-01-20 22:18:01 -03:30
Finixhed applying jsHint linting to js files. Created initial Gruntfile.js build script and package.json script for keeping track of required node modules.
This commit is contained in:
parent
f891c30ebb
commit
d25e712e21
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,6 +7,7 @@ awx/public/static
|
||||
awx/ui/static/js/awx-min.js
|
||||
awx/ui/static/css/awx.min.css
|
||||
env/*
|
||||
node_modules/**
|
||||
build
|
||||
deb-build
|
||||
dist
|
||||
|
||||
32
Gruntfile.js
Normal file
32
Gruntfile.js
Normal file
@ -0,0 +1,32 @@
|
||||
module.exports = function(grunt) {
|
||||
|
||||
grunt.initConfig({
|
||||
|
||||
pkg: grunt.file.readJSON('./package.json'),
|
||||
|
||||
jshint: {
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
},
|
||||
uses_defaults: ['awx/ui/static/js/*','awx/ui/static/lib/ansible/*', '!awx/ui/static/js/awx-min.js']
|
||||
},
|
||||
|
||||
uglify: {
|
||||
options: {
|
||||
banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
|
||||
'<%= grunt.template.today("yyyy-mm-dd") %> */'
|
||||
},
|
||||
my_target: {
|
||||
files: {
|
||||
'awx/ui/static/js/awx-min.js': ['awx/ui/static/js/**/*.js', 'awx/ui/static/lib/ansible/*.js',
|
||||
'!awx/ui/static/js/awx-min.js']
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
|
||||
grunt.registerTask('default', ['jshint', 'uglify']);
|
||||
}
|
||||
@ -4,23 +4,22 @@
|
||||
* Our main application mdoule. Declare application routes and perform initialization chores.
|
||||
*
|
||||
*/
|
||||
|
||||
var urlPrefix = $basePath;
|
||||
|
||||
angular.module('ansible', [
|
||||
'RestServices',
|
||||
'AuthService',
|
||||
'Utilities',
|
||||
'OrganizationFormDefinition',
|
||||
'OrganizationFormDefinition',
|
||||
'UserFormDefinition',
|
||||
'FormGenerator',
|
||||
'OrganizationListDefinition',
|
||||
'UserListDefinition',
|
||||
'UserListDefinition',
|
||||
'UserHelper',
|
||||
'ListGenerator',
|
||||
'ListGenerator',
|
||||
'PromptDialog',
|
||||
'ApiLoader',
|
||||
'RelatedSearchHelper',
|
||||
'ApiLoader',
|
||||
'RelatedSearchHelper',
|
||||
'SearchHelper',
|
||||
'PaginationHelpers',
|
||||
'RefreshHelper',
|
||||
@ -58,6 +57,7 @@ angular.module('ansible', [
|
||||
'JobFormDefinition',
|
||||
'JobEventsListDefinition',
|
||||
'JobEventDataDefinition',
|
||||
'JobEventsFormDefinition',
|
||||
'JobHostDefinition',
|
||||
'JobSummaryDefinition',
|
||||
'ParseHelper',
|
||||
@ -75,9 +75,7 @@ angular.module('ansible', [
|
||||
'ObjectCountWidget',
|
||||
'StreamWidget',
|
||||
'JobsHelper',
|
||||
'InventoryStatusDefinition',
|
||||
'InventoryGroupsHelpDefinition',
|
||||
'InventoryHostsHelpDefinition',
|
||||
'InventoryTree',
|
||||
'CredentialsHelper',
|
||||
'TimerService',
|
||||
@ -85,253 +83,368 @@ angular.module('ansible', [
|
||||
'HomeGroupListDefinition',
|
||||
'HomeHostListDefinition',
|
||||
'ActivityDetailDefinition'
|
||||
])
|
||||
.config(['$routeProvider', function($routeProvider) {
|
||||
$routeProvider.
|
||||
when('/jobs',
|
||||
{ templateUrl: urlPrefix + 'partials/jobs.html', controller: JobsListCtrl }).
|
||||
])
|
||||
.config(['$routeProvider',
|
||||
function ($routeProvider) {
|
||||
$routeProvider.
|
||||
when('/jobs', {
|
||||
templateUrl: urlPrefix + 'partials/jobs.html',
|
||||
controller: 'JobsListCtrl'
|
||||
}).
|
||||
|
||||
when('/jobs/:id',
|
||||
{ templateUrl: urlPrefix + 'partials/jobs.html', controller: JobsEdit }).
|
||||
when('/jobs/:id', {
|
||||
templateUrl: urlPrefix + 'partials/jobs.html',
|
||||
controller: 'JobsEdit'
|
||||
}).
|
||||
|
||||
when('/jobs/:id/job_events',
|
||||
{ templateUrl: urlPrefix + 'partials/jobs.html', controller: JobEventsList }).
|
||||
when('/jobs/:id/job_events', {
|
||||
templateUrl: urlPrefix + 'partials/jobs.html',
|
||||
controller: 'JobEventsList'
|
||||
}).
|
||||
|
||||
when('/jobs/:id/job_host_summaries',
|
||||
{ templateUrl: urlPrefix + 'partials/jobs.html', controller: JobHostSummaryList }).
|
||||
|
||||
when('/jobs/:job_id/job_events/:event_id',
|
||||
{ templateUrl: urlPrefix + 'partials/jobs.html', controller: JobEventsEdit }).
|
||||
when('/jobs/:id/job_host_summaries', {
|
||||
templateUrl: urlPrefix + 'partials/jobs.html',
|
||||
controller: 'JobHostSummaryList'
|
||||
}).
|
||||
|
||||
when('/job_templates',
|
||||
{ templateUrl: urlPrefix + 'partials/job_templates.html', controller: JobTemplatesList }).
|
||||
|
||||
when('/job_templates/add',
|
||||
{ templateUrl: urlPrefix + 'partials/job_templates.html', controller: JobTemplatesAdd }).
|
||||
when('/jobs/:job_id/job_events/:event_id', {
|
||||
templateUrl: urlPrefix + 'partials/jobs.html',
|
||||
controller: 'JobEventsEdit'
|
||||
}).
|
||||
|
||||
when('/job_templates/:id',
|
||||
{ templateUrl: urlPrefix + 'partials/job_templates.html', controller: JobTemplatesEdit }).
|
||||
when('/job_templates', {
|
||||
templateUrl: urlPrefix + 'partials/job_templates.html',
|
||||
controller: 'JobTemplatesList'
|
||||
}).
|
||||
|
||||
when('/projects',
|
||||
{ templateUrl: urlPrefix + 'partials/projects.html', controller: ProjectsList }).
|
||||
when('/job_templates/add', {
|
||||
templateUrl: urlPrefix + 'partials/job_templates.html',
|
||||
controller: 'JobTemplatesAdd'
|
||||
}).
|
||||
|
||||
when('/projects/add',
|
||||
{ templateUrl: urlPrefix + 'partials/projects.html', controller: ProjectsAdd }).
|
||||
when('/job_templates/:id', {
|
||||
templateUrl: urlPrefix + 'partials/job_templates.html',
|
||||
controller: 'JobTemplatesEdit'
|
||||
}).
|
||||
|
||||
when('/projects/:id',
|
||||
{ templateUrl: urlPrefix + 'partials/projects.html', controller: ProjectsEdit }).
|
||||
when('/projects', {
|
||||
templateUrl: urlPrefix + 'partials/projects.html',
|
||||
controller: 'ProjectsList'
|
||||
}).
|
||||
|
||||
when('/projects/:project_id/organizations',
|
||||
{ templateUrl: urlPrefix + 'partials/projects.html', controller: OrganizationsList }).
|
||||
when('/projects/add', {
|
||||
templateUrl: urlPrefix + 'partials/projects.html',
|
||||
controller: 'ProjectsAdd'
|
||||
}).
|
||||
|
||||
when('/projects/:project_id/organizations/add',
|
||||
{ templateUrl: urlPrefix + 'partials/projects.html', controller: OrganizationsAdd }).
|
||||
when('/projects/:id', {
|
||||
templateUrl: urlPrefix + 'partials/projects.html',
|
||||
controller: 'ProjectsEdit'
|
||||
}).
|
||||
|
||||
when('/hosts/:id/job_host_summaries',
|
||||
{ templateUrl: urlPrefix + 'partials/jobs.html', controller: JobHostSummaryList }).
|
||||
when('/projects/:project_id/organizations', {
|
||||
templateUrl: urlPrefix + 'partials/projects.html',
|
||||
controller: 'OrganizationsList'
|
||||
}).
|
||||
|
||||
when('/inventories',
|
||||
{ templateUrl: urlPrefix + 'partials/inventories.html', controller: InventoriesList }).
|
||||
when('/projects/:project_id/organizations/add', {
|
||||
templateUrl: urlPrefix + 'partials/projects.html',
|
||||
controller: 'OrganizationsAdd'
|
||||
}).
|
||||
|
||||
when('/inventories/add',
|
||||
{ templateUrl: urlPrefix + 'partials/inventories.html', controller: InventoriesAdd }).
|
||||
when('/hosts/:id/job_host_summaries', {
|
||||
templateUrl: urlPrefix + 'partials/jobs.html',
|
||||
controller: 'JobHostSummaryList'
|
||||
}).
|
||||
|
||||
when('/inventories/:inventory_id',
|
||||
{ templateUrl: urlPrefix + 'partials/inventory-edit.html', controller: InventoriesEdit }).
|
||||
when('/inventories', {
|
||||
templateUrl: urlPrefix + 'partials/inventories.html',
|
||||
controller: 'InventoriesList'
|
||||
}).
|
||||
|
||||
when('/organizations', { templateUrl: urlPrefix + 'partials/organizations.html',
|
||||
controller: OrganizationsList }).
|
||||
when('/inventories/add', {
|
||||
templateUrl: urlPrefix + 'partials/inventories.html',
|
||||
controller: 'InventoriesAdd'
|
||||
}).
|
||||
|
||||
when('/organizations/add', { templateUrl: urlPrefix + 'partials/organizations.html',
|
||||
controller: OrganizationsAdd }).
|
||||
when('/inventories/:inventory_id', {
|
||||
templateUrl: urlPrefix + 'partials/inventory-edit.html',
|
||||
controller: 'InventoriesEdit'
|
||||
}).
|
||||
|
||||
when('/organizations/:organization_id', { templateUrl: urlPrefix + 'partials/organizations.html',
|
||||
controller: OrganizationsEdit }).
|
||||
when('/organizations', {
|
||||
templateUrl: urlPrefix + 'partials/organizations.html',
|
||||
controller: 'OrganizationsList'
|
||||
}).
|
||||
|
||||
when('/organizations/:organization_id/admins', { templateUrl: urlPrefix + 'partials/organizations.html',
|
||||
controller: AdminsList }).
|
||||
when('/organizations/add', {
|
||||
templateUrl: urlPrefix + 'partials/organizations.html',
|
||||
controller: 'OrganizationsAdd'
|
||||
}).
|
||||
|
||||
when('/organizations/:organization_id/users', { templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: UsersList }).
|
||||
when('/organizations/:organization_id', {
|
||||
templateUrl: urlPrefix + 'partials/organizations.html',
|
||||
controller: 'OrganizationsEdit'
|
||||
}).
|
||||
|
||||
when('/organizations/:organization_id/users/add', { templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: UsersAdd }).
|
||||
when('/organizations/:organization_id/admins', {
|
||||
templateUrl: urlPrefix + 'partials/organizations.html',
|
||||
controller: 'AdminsList'
|
||||
}).
|
||||
|
||||
when('/organizations/:organization_id/users/:user_id', { templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: UsersEdit }).
|
||||
when('/organizations/:organization_id/users', {
|
||||
templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: 'UsersList'
|
||||
}).
|
||||
|
||||
when('/teams', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: TeamsList }).
|
||||
when('/organizations/:organization_id/users/add', {
|
||||
templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: 'UsersAdd'
|
||||
}).
|
||||
|
||||
when('/teams/add', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: TeamsAdd }).
|
||||
when('/organizations/:organization_id/users/:user_id', {
|
||||
templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: 'UsersEdit'
|
||||
}).
|
||||
|
||||
when('/teams/:team_id', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: TeamsEdit }).
|
||||
|
||||
when('/teams/:team_id/permissions/add', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: PermissionsAdd }).
|
||||
when('/teams', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'TeamsList'
|
||||
}).
|
||||
|
||||
when('/teams/:team_id/permissions', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: PermissionsList }).
|
||||
when('/teams/add', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'TeamsAdd'
|
||||
}).
|
||||
|
||||
when('/teams/:team_id/permissions/:permission_id', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: PermissionsEdit }).
|
||||
when('/teams/:team_id', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'TeamsEdit'
|
||||
}).
|
||||
|
||||
when('/teams/:team_id/users', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: UsersList }).
|
||||
when('/teams/:team_id/permissions/add', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'PermissionsAdd'
|
||||
}).
|
||||
|
||||
when('/teams/:team_id/users/:user_id', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: UsersEdit }).
|
||||
when('/teams/:team_id/permissions', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'PermissionsList'
|
||||
}).
|
||||
|
||||
when('/teams/:team_id/projects', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: ProjectsList }).
|
||||
when('/teams/:team_id/permissions/:permission_id', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'PermissionsEdit'
|
||||
}).
|
||||
|
||||
when('/teams/:team_id/projects/add', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: ProjectsAdd }).
|
||||
when('/teams/:team_id/users', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'UsersList'
|
||||
}).
|
||||
|
||||
when('/teams/:team_id/projects/:project_id', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: ProjectsEdit }).
|
||||
|
||||
when('/teams/:team_id/credentials', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: CredentialsList }).
|
||||
when('/teams/:team_id/users/:user_id', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'UsersEdit'
|
||||
}).
|
||||
|
||||
when('/teams/:team_id/credentials/add', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: CredentialsAdd }).
|
||||
when('/teams/:team_id/projects', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'ProjectsList'
|
||||
}).
|
||||
|
||||
when('/teams/:team_id/credentials/:credential_id', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: CredentialsEdit }).
|
||||
when('/teams/:team_id/projects/add', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'ProjectsAdd'
|
||||
}).
|
||||
|
||||
when('/credentials', { templateUrl: urlPrefix + 'partials/credentials.html',
|
||||
controller: CredentialsList }).
|
||||
when('/teams/:team_id/projects/:project_id', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'ProjectsEdit'
|
||||
}).
|
||||
|
||||
when('/credentials/add', { templateUrl: urlPrefix + 'partials/credentials.html',
|
||||
controller: CredentialsAdd }).
|
||||
when('/teams/:team_id/credentials', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'CredentialsList'
|
||||
}).
|
||||
|
||||
when('/credentials/:credential_id', { templateUrl: urlPrefix + 'partials/credentials.html',
|
||||
controller: CredentialsEdit }).
|
||||
|
||||
when('/users', { templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: UsersList }).
|
||||
when('/teams/:team_id/credentials/add', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'CredentialsAdd'
|
||||
}).
|
||||
|
||||
when('/users/add', { templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: UsersAdd }).
|
||||
when('/teams/:team_id/credentials/:credential_id', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'CredentialsEdit'
|
||||
}).
|
||||
|
||||
when('/users/:user_id', { templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: UsersEdit }).
|
||||
when('/credentials', {
|
||||
templateUrl: urlPrefix + 'partials/credentials.html',
|
||||
controller: 'CredentialsList'
|
||||
}).
|
||||
|
||||
when('/users/:user_id/credentials', { templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: CredentialsList }).
|
||||
when('/credentials/add', {
|
||||
templateUrl: urlPrefix + 'partials/credentials.html',
|
||||
controller: 'CredentialsAdd'
|
||||
}).
|
||||
|
||||
when('/users/:user_id/permissions/add', { templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: PermissionsAdd }).
|
||||
when('/credentials/:credential_id', {
|
||||
templateUrl: urlPrefix + 'partials/credentials.html',
|
||||
controller: 'CredentialsEdit'
|
||||
}).
|
||||
|
||||
when('/users/:user_id/permissions', { templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: PermissionsList }).
|
||||
when('/users', {
|
||||
templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: 'UsersList'
|
||||
}).
|
||||
|
||||
when('/users/:user_id/permissions/:permission_id', { templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: PermissionsEdit }).
|
||||
when('/users/add', {
|
||||
templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: 'UsersAdd'
|
||||
}).
|
||||
|
||||
when('/users/:user_id/credentials/add', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: CredentialsAdd }).
|
||||
when('/users/:user_id', {
|
||||
templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: 'UsersEdit'
|
||||
}).
|
||||
|
||||
when('/teams/:user_id/credentials/:credential_id', { templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: CredentialsEdit }).
|
||||
when('/users/:user_id/credentials', {
|
||||
templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: 'CredentialsList'
|
||||
}).
|
||||
|
||||
when('/login', { templateUrl: urlPrefix + 'partials/home.html', controller: Authenticate }).
|
||||
when('/users/:user_id/permissions/add', {
|
||||
templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: 'PermissionsAdd'
|
||||
}).
|
||||
|
||||
when('/logout', { templateUrl: urlPrefix + 'partials/home.html', controller: Authenticate }).
|
||||
when('/users/:user_id/permissions', {
|
||||
templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: 'PermissionsList'
|
||||
}).
|
||||
|
||||
when('/home', { templateUrl: urlPrefix + 'partials/home.html', controller: Home }).
|
||||
when('/users/:user_id/permissions/:permission_id', {
|
||||
templateUrl: urlPrefix + 'partials/users.html',
|
||||
controller: 'PermissionsEdit'
|
||||
}).
|
||||
|
||||
when('/home/groups', { templateUrl: urlPrefix + 'partials/subhome.html', controller: HomeGroups }).
|
||||
when('/users/:user_id/credentials/add', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'CredentialsAdd'
|
||||
}).
|
||||
|
||||
when('/home/hosts', { templateUrl: urlPrefix + 'partials/subhome.html', controller: HomeHosts }).
|
||||
|
||||
otherwise({redirectTo: '/home'});
|
||||
}])
|
||||
.run(['$cookieStore', '$rootScope', 'CheckLicense', '$location', 'Authorization','LoadBasePaths', 'ViewLicense',
|
||||
'Timer', 'ClearScope', 'HideStream',
|
||||
function($cookieStore, $rootScope, CheckLicense, $location, Authorization, LoadBasePaths, ViewLicense,
|
||||
Timer, ClearScope, HideStream) {
|
||||
|
||||
LoadBasePaths();
|
||||
|
||||
$rootScope.breadcrumbs = new Array();
|
||||
$rootScope.crumbCache = new Array();
|
||||
$rootScope.sessionTimer = Timer.init();
|
||||
when('/teams/:user_id/credentials/:credential_id', {
|
||||
templateUrl: urlPrefix + 'partials/teams.html',
|
||||
controller: 'CredentialsEdit'
|
||||
}).
|
||||
|
||||
$rootScope.$on("$routeChangeStart", function(event, next, current) {
|
||||
when('/login', {
|
||||
templateUrl: urlPrefix + 'partials/home.html',
|
||||
controller: 'Authenticate'
|
||||
}).
|
||||
|
||||
// Before navigating away from current tab, make sure the primary view is visible
|
||||
if ($('#stream-container').is(':visible')) {
|
||||
HideStream();
|
||||
}
|
||||
when('/logout', {
|
||||
templateUrl: urlPrefix + 'partials/home.html',
|
||||
controller: 'Authenticate'
|
||||
}).
|
||||
|
||||
// On each navigation request, check that the user is logged in
|
||||
if ( !/^\/(login|logout)/.test($location.path()) ) {
|
||||
// capture most recent URL, excluding login/logout
|
||||
$rootScope.lastPath = $location.path();
|
||||
$cookieStore.put('lastPath', $location.path());
|
||||
}
|
||||
when('/home', {
|
||||
templateUrl: urlPrefix + 'partials/home.html',
|
||||
controller: 'Home'
|
||||
}).
|
||||
|
||||
if (Authorization.isUserLoggedIn() == false) {
|
||||
if ( next.templateUrl != (urlPrefix + 'partials/login.html') ) {
|
||||
$location.path('/login');
|
||||
}
|
||||
}
|
||||
else if ($rootScope.sessionTimer.isExpired()) {
|
||||
if ( next.templateUrl != (urlPrefix + 'partials/login.html') ) {
|
||||
$rootScope.sessionTimer.expireSession();
|
||||
$location.path('/login');
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($rootScope.current_user == undefined || $rootScope.current_user == null) {
|
||||
Authorization.restoreUserInfo(); //user must have hit browser refresh
|
||||
}
|
||||
CheckLicense();
|
||||
}
|
||||
|
||||
// Make the correct tab active
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
if (base == '') {
|
||||
base = 'home';
|
||||
}
|
||||
else {
|
||||
base.replace(/\_/g,' ');
|
||||
}
|
||||
$('.nav-tabs a[href="#' + base + '"]').tab('show');
|
||||
when('/home/groups', {
|
||||
templateUrl: urlPrefix + 'partials/subhome.html',
|
||||
controller: 'HomeGroups'
|
||||
}).
|
||||
|
||||
when('/home/hosts', {
|
||||
templateUrl: urlPrefix + 'partials/subhome.html',
|
||||
controller: 'HomeHosts'
|
||||
}).
|
||||
|
||||
otherwise({
|
||||
redirectTo: '/home'
|
||||
});
|
||||
}
|
||||
])
|
||||
.run(['$cookieStore', '$rootScope', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'ViewLicense',
|
||||
'Timer', 'ClearScope', 'HideStream',
|
||||
function ($cookieStore, $rootScope, CheckLicense, $location, Authorization, LoadBasePaths, ViewLicense,
|
||||
Timer, ClearScope, HideStream) {
|
||||
|
||||
LoadBasePaths();
|
||||
|
||||
$rootScope.breadcrumbs = [];
|
||||
$rootScope.crumbCache = [];
|
||||
$rootScope.sessionTimer = Timer.init();
|
||||
|
||||
$rootScope.$on("$routeChangeStart", function (event, next) {
|
||||
|
||||
// Before navigating away from current tab, make sure the primary view is visible
|
||||
if ($('#stream-container').is(':visible')) {
|
||||
HideStream();
|
||||
}
|
||||
|
||||
// On each navigation request, check that the user is logged in
|
||||
if (!/^\/(login|logout)/.test($location.path())) {
|
||||
// capture most recent URL, excluding login/logout
|
||||
$rootScope.lastPath = $location.path();
|
||||
$cookieStore.put('lastPath', $location.path());
|
||||
}
|
||||
|
||||
if (Authorization.isUserLoggedIn() === false) {
|
||||
if (next.templateUrl !== (urlPrefix + 'partials/login.html')) {
|
||||
$location.path('/login');
|
||||
}
|
||||
} else if ($rootScope.sessionTimer.isExpired()) {
|
||||
if (next.templateUrl !== (urlPrefix + 'partials/login.html')) {
|
||||
$rootScope.sessionTimer.expireSession();
|
||||
$location.path('/login');
|
||||
}
|
||||
} else {
|
||||
if ($rootScope.current_user === undefined || $rootScope.current_user === null) {
|
||||
Authorization.restoreUserInfo(); //user must have hit browser refresh
|
||||
}
|
||||
CheckLicense();
|
||||
}
|
||||
|
||||
// Make the correct tab active
|
||||
var base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
if (base === '') {
|
||||
base = 'home';
|
||||
} else {
|
||||
base.replace(/\_/g, ' ');
|
||||
}
|
||||
$('.nav-tabs a[href="#' + base + '"]').tab('show');
|
||||
});
|
||||
|
||||
if (!Authorization.getToken()) {
|
||||
// When the app first loads, redirect to login page
|
||||
$rootScope.sessionExpired = false;
|
||||
$cookieStore.put('sessionExpired', false);
|
||||
$location.path('/login');
|
||||
}
|
||||
else {
|
||||
// If browser refresh, set the user_is_superuser value
|
||||
$rootScope['user_is_superuser'] = Authorization.getUserInfo('is_superuser');
|
||||
}
|
||||
|
||||
// If browser refresh, activate the correct tab
|
||||
var base = ($location.path().replace(/^\//,'').split('/')[0]);
|
||||
if (base == '') {
|
||||
base = 'home';
|
||||
$location.path('/home');
|
||||
}
|
||||
else {
|
||||
base.replace(/\_/g,' ');
|
||||
}
|
||||
$('.nav-tabs a[href="#' + base + '"]').tab('show');
|
||||
|
||||
$rootScope.viewCurrentUser = function() {
|
||||
$location.path('/users/' + $rootScope.current_user.id);
|
||||
if (!Authorization.getToken()) {
|
||||
// When the app first loads, redirect to login page
|
||||
$rootScope.sessionExpired = false;
|
||||
$cookieStore.put('sessionExpired', false);
|
||||
$location.path('/login');
|
||||
} else {
|
||||
// If browser refresh, set the user_is_superuser value
|
||||
$rootScope.user_is_superuser = Authorization.getUserInfo('is_superuser');
|
||||
}
|
||||
|
||||
$rootScope.viewLicense = function() {
|
||||
//$location.path('/license');
|
||||
ViewLicense();
|
||||
}
|
||||
}]);
|
||||
// If browser refresh, activate the correct tab
|
||||
var base = ($location.path().replace(/^\//, '').split('/')[0]);
|
||||
if (base === '') {
|
||||
base = 'home';
|
||||
$location.path('/home');
|
||||
} else {
|
||||
base.replace(/\_/g, ' ');
|
||||
}
|
||||
$('.nav-tabs a[href="#' + base + '"]').tab('show');
|
||||
|
||||
$rootScope.viewCurrentUser = function () {
|
||||
$location.path('/users/' + $rootScope.current_user.id);
|
||||
};
|
||||
|
||||
$rootScope.viewLicense = function () {
|
||||
//$location.path('/license');
|
||||
ViewLicense();
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -1,4 +1,4 @@
|
||||
/************************************
|
||||
/**********************************************************************
|
||||
*
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
@ -8,19 +8,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
var $AnsibleConfig =
|
||||
{
|
||||
tooltip_delay: {show: 500, hide: 100}, // Default number of milliseconds to delay displaying/hiding tooltips
|
||||
/*jshint unused:false */
|
||||
|
||||
debug_mode: true, // Enable console logging messages
|
||||
|
||||
password_strength: 45, // User password strength. Integer between 0 and 100, 100 being impossibly strong.
|
||||
// This value controls progress bar colors:
|
||||
// 0 to password_strength - 15 = red;
|
||||
// password_strength - 15 to password_strength = yellow
|
||||
// > password_strength = green
|
||||
// It also controls password validation. Passwords are rejected if the score is not > password_strength.
|
||||
var $AnsibleConfig = {
|
||||
|
||||
session_timeout: 1800 // Number of seconds before an inactive session is automatically timed out and forced to log in again.
|
||||
// Separate from time out value set in API.
|
||||
}
|
||||
tooltip_delay: {show: 500, hide: 100}, // Default number of milliseconds to delay displaying/hiding tooltips
|
||||
|
||||
debug_mode: true, // Enable console logging messages
|
||||
|
||||
password_strength: 45, // User password strength. Integer between 0 and 100, 100 being impossibly strong.
|
||||
// This value controls progress bar colors:
|
||||
// 0 to password_strength - 15 = red;
|
||||
// password_strength - 15 to password_strength = yellow
|
||||
// > password_strength = green
|
||||
// It also controls password validation. Passwords are rejected if the score is not > password_strength.
|
||||
|
||||
session_timeout: 1800 // Number of seconds before an inactive session is automatically timed out and forced to log in again.
|
||||
// Separate from time out value set in API.
|
||||
};
|
||||
@ -1,12 +1,12 @@
|
||||
/************************************
|
||||
/*************************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
*
|
||||
* Credentials.js
|
||||
*
|
||||
* Controller functions for the Credential model.
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
function CredentialsList($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, CredentialList,
|
||||
@ -114,10 +114,10 @@ function CredentialsList($scope, $rootScope, $location, $log, $routeParams, Rest
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success(function (data, status, headers, config) {
|
||||
.success(function () {
|
||||
scope.search(list.iterator);
|
||||
})
|
||||
.error(function (data, status, headers, config) {
|
||||
.error(function (data, status) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
@ -143,7 +143,7 @@ CredentialsList.$inject = ['$scope', '$rootScope', '$location', '$log', '$routeP
|
||||
function CredentialsAdd($scope, $rootScope, $compile, $location, $log, $routeParams, CredentialForm,
|
||||
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope,
|
||||
GenerateList, SearchInit, PaginateInit, LookUpInit, UserList, TeamList, GetBasePath,
|
||||
GetChoices, Empty, KindChange, OwnerChange, FormSave, DebugForm) {
|
||||
GetChoices, Empty, KindChange, OwnerChange, FormSave) {
|
||||
ClearScope('tree-form');
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
@ -152,7 +152,6 @@ function CredentialsAdd($scope, $rootScope, $compile, $location, $log, $routePar
|
||||
var form = CredentialForm,
|
||||
generator = GenerateForm,
|
||||
scope = generator.inject(form, { mode: 'add', related: false }),
|
||||
base = $location.path().replace(/^\//, '').split('/')[0],
|
||||
defaultUrl = GetBasePath('credentials'),
|
||||
url;
|
||||
|
||||
@ -193,10 +192,10 @@ function CredentialsAdd($scope, $rootScope, $compile, $location, $log, $routePar
|
||||
url = GetBasePath('users') + $routeParams.user_id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function (data, status, headers, config) {
|
||||
.success(function (data) {
|
||||
scope.user_username = data.username;
|
||||
})
|
||||
.error(function (data, status, headers, config) {
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve user. GET status: ' + status
|
||||
});
|
||||
});
|
||||
@ -210,10 +209,10 @@ function CredentialsAdd($scope, $rootScope, $compile, $location, $log, $routePar
|
||||
url = GetBasePath('teams') + $routeParams.team_id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function (data, status, headers, config) {
|
||||
.success(function (data) {
|
||||
scope.team_name = data.name;
|
||||
})
|
||||
.error(function (data, status, headers, config) {
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve team. GET status: ' + status
|
||||
});
|
||||
});
|
||||
@ -289,7 +288,7 @@ function CredentialsAdd($scope, $rootScope, $compile, $location, $log, $routePar
|
||||
CredentialsAdd.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'CredentialForm', 'GenerateForm',
|
||||
'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'GenerateList',
|
||||
'SearchInit', 'PaginateInit', 'LookUpInit', 'UserList', 'TeamList', 'GetBasePath', 'GetChoices', 'Empty',
|
||||
'KindChange', 'OwnerChange', 'FormSave', 'DebugForm'
|
||||
'KindChange', 'OwnerChange', 'FormSave'
|
||||
];
|
||||
|
||||
|
||||
|
||||
@ -249,13 +249,12 @@ JobEventsList.$inject = ['$filter', '$scope', '$rootScope', '$location', '$log',
|
||||
'ProcessErrors', 'GetBasePath', 'LookUpInit', 'ToggleChildren', 'FormatDate', 'EventView', 'Refresh', 'Wait'
|
||||
];
|
||||
|
||||
function JobEventsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, JobEventForm, GenerateForm,
|
||||
Rest, Alert, ProcessErrors, LoadBreadCrumbs, ClearScope, GetBasePath, FormatDate, EventView,
|
||||
Wait) {
|
||||
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
|
||||
//scope.
|
||||
// Inject dynamic view
|
||||
var form = JobEventForm,
|
||||
function JobEventsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, JobEventsForm, GenerateForm,
|
||||
Rest, Alert, ProcessErrors, LoadBreadCrumbs, ClearScope, GetBasePath, FormatDate, EventView, Wait) {
|
||||
|
||||
ClearScope('htmlTemplate');
|
||||
|
||||
var form = JobEventsForm,
|
||||
generator = GenerateForm,
|
||||
scope = GenerateForm.inject(form, { mode: 'edit', related: true }),
|
||||
defaultUrl = GetBasePath('base') + 'job_events/' + $routeParams.event_id + '/';
|
||||
@ -348,7 +347,7 @@ function JobEventsEdit($scope, $rootScope, $compile, $location, $log, $routePara
|
||||
|
||||
}
|
||||
|
||||
JobEventsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobEventForm',
|
||||
JobEventsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobEventsForm',
|
||||
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ClearScope', 'GetBasePath', 'FormatDate',
|
||||
'EventView', 'Wait'
|
||||
];
|
||||
@ -6,11 +6,10 @@
|
||||
*
|
||||
*/
|
||||
angular.module('ActivityDetailDefinition', [])
|
||||
.value(
|
||||
'ActivityDetailForm', {
|
||||
|
||||
.value('ActivityDetailForm', {
|
||||
|
||||
name: 'activity',
|
||||
editTitle: 'Activity Detail',
|
||||
editTitle: 'Activity Detail',
|
||||
well: false,
|
||||
'class': 'horizontal-narrow',
|
||||
formFieldSize: 'col-lg-10',
|
||||
@ -21,18 +20,18 @@ angular.module('ActivityDetailDefinition', [])
|
||||
label: "Initiated by",
|
||||
type: 'text',
|
||||
readonly: true
|
||||
},
|
||||
},
|
||||
operation: {
|
||||
label: 'Action',
|
||||
type: 'text',
|
||||
readonly: true
|
||||
},
|
||||
},
|
||||
changes: {
|
||||
label: 'Changes',
|
||||
type: 'textarea',
|
||||
ngHide: "!changes || changes =='' || changes == 'null'",
|
||||
readonly: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}); //Form
|
||||
|
||||
@ -6,23 +6,22 @@
|
||||
*
|
||||
*/
|
||||
angular.module('CredentialFormDefinition', [])
|
||||
.value(
|
||||
'CredentialForm', {
|
||||
|
||||
addTitle: 'Create Credential', //Legend in add mode
|
||||
editTitle: '{{ name }}', //Legend in edit mode
|
||||
.value('CredentialForm', {
|
||||
|
||||
addTitle: 'Create Credential', //Legend in add mode
|
||||
editTitle: '{{ name }}', //Legend in edit mode
|
||||
name: 'credential',
|
||||
well: true,
|
||||
forceListeners: true,
|
||||
|
||||
|
||||
actions: {
|
||||
stream: {
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
mode: 'edit'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
label: 'Name',
|
||||
@ -30,27 +29,31 @@ angular.module('CredentialFormDefinition', [])
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
autocomplete: false
|
||||
},
|
||||
description: {
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
editRequired: false
|
||||
},
|
||||
},
|
||||
owner: {
|
||||
label: "Does this credential belong to a team or user?",
|
||||
type: 'radio_group',
|
||||
ngChange: "ownerChange()",
|
||||
options: [
|
||||
{ label: 'User', value: 'user', selected: true },
|
||||
{ label: 'Team', value: 'team' }
|
||||
],
|
||||
awPopOver: "<p>A credential must be associated with either a user or a team. Choosing a user allows only the selected user access " +
|
||||
options: [{
|
||||
label: 'User',
|
||||
value: 'user',
|
||||
selected: true
|
||||
}, {
|
||||
label: 'Team',
|
||||
value: 'team'
|
||||
}],
|
||||
awPopOver: "<p>A credential must be associated with either a user or a team. Choosing a user allows only the selected user access " +
|
||||
"to the credential. Choosing a team shares the credential with all team members.</p>",
|
||||
dataTitle: 'Owner',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
user: {
|
||||
label: 'User that owns this credential',
|
||||
type: 'lookup',
|
||||
@ -58,8 +61,11 @@ angular.module('CredentialFormDefinition', [])
|
||||
sourceField: 'username',
|
||||
ngClick: 'lookUpUser()',
|
||||
ngShow: "owner == 'user'",
|
||||
awRequiredWhen: { variable: "user_required", init: "false" }
|
||||
},
|
||||
awRequiredWhen: {
|
||||
variable: "user_required",
|
||||
init: "false"
|
||||
}
|
||||
},
|
||||
team: {
|
||||
label: 'Team that owns this credential',
|
||||
type: 'lookup',
|
||||
@ -67,69 +73,84 @@ angular.module('CredentialFormDefinition', [])
|
||||
sourceField: 'name',
|
||||
ngClick: 'lookUpTeam()',
|
||||
ngShow: "owner == 'team'",
|
||||
awRequiredWhen: { variable: "team_required", init: "false" }
|
||||
},
|
||||
awRequiredWhen: {
|
||||
variable: "team_required",
|
||||
init: "false"
|
||||
}
|
||||
},
|
||||
kind: {
|
||||
label: 'Type',
|
||||
excludeModal: true,
|
||||
type: 'select',
|
||||
ngOptions: 'kind.label for kind in credential_kind_options',
|
||||
ngChange: 'kindChange()',
|
||||
addRequired: true,
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
helpCollapse: [
|
||||
{ hdr: 'Select a Credential Type',
|
||||
content: '<dl>\n' +
|
||||
'<dt>AWS</dt>\n' +
|
||||
'<dd>Access keys for Amazon Web Services used for inventory management or deployment.</dd>\n' +
|
||||
'<dt>Machine</dt>\n' +
|
||||
'<dd>Authentication for remote machine access. This can include SSH keys, usernames, passwords, ' +
|
||||
'and sudo information. Machine credentials are used when submitting jobs to run playbooks against ' +
|
||||
'remote hosts.</dd>' +
|
||||
'<dt>Rackspace</dt>\n' +
|
||||
'<dd>Access information for Rackspace Cloud used for inventory management or deployment.</dd>\n' +
|
||||
'<dt>SCM</dt>\n' +
|
||||
'<dd>Used to check out and synchronize playbook repositories with a remote source control ' +
|
||||
'management system such as Git, Subversion (svn), or Mercurial (hg). These credentials are ' +
|
||||
'used on the Projects tab.</dd>\n' +
|
||||
'</dl>\n'
|
||||
}]
|
||||
},
|
||||
helpCollapse: [{
|
||||
hdr: 'Select a Credential Type',
|
||||
content: '<dl>\n' +
|
||||
'<dt>AWS</dt>\n' +
|
||||
'<dd>Access keys for Amazon Web Services used for inventory management or deployment.</dd>\n' +
|
||||
'<dt>Machine</dt>\n' +
|
||||
'<dd>Authentication for remote machine access. This can include SSH keys, usernames, passwords, ' +
|
||||
'and sudo information. Machine credentials are used when submitting jobs to run playbooks against ' +
|
||||
'remote hosts.</dd>' +
|
||||
'<dt>Rackspace</dt>\n' +
|
||||
'<dd>Access information for Rackspace Cloud used for inventory management or deployment.</dd>\n' +
|
||||
'<dt>SCM</dt>\n' +
|
||||
'<dd>Used to check out and synchronize playbook repositories with a remote source control ' +
|
||||
'management system such as Git, Subversion (svn), or Mercurial (hg). These credentials are ' +
|
||||
'used on the Projects tab.</dd>\n' +
|
||||
'</dl>\n'
|
||||
}]
|
||||
},
|
||||
access_key: {
|
||||
label: 'Access Key',
|
||||
type: 'text',
|
||||
ngShow: "kind.value == 'aws'",
|
||||
awRequiredWhen: { variable: "aws_required", init: false },
|
||||
awRequiredWhen: {
|
||||
variable: "aws_required",
|
||||
init: false
|
||||
},
|
||||
autocomplete: false,
|
||||
apiField: 'username'
|
||||
},
|
||||
},
|
||||
secret_key: {
|
||||
label: 'Secret Key',
|
||||
type: 'password',
|
||||
ngShow: "kind.value == 'aws'",
|
||||
awRequiredWhen: { variable: "aws_required", init: false },
|
||||
awRequiredWhen: {
|
||||
variable: "aws_required",
|
||||
init: false
|
||||
},
|
||||
autocomplete: false,
|
||||
ask: false,
|
||||
clear: false,
|
||||
apiField: 'passwowrd'
|
||||
},
|
||||
},
|
||||
"username": {
|
||||
labelBind: 'usernameLabel',
|
||||
type: 'text',
|
||||
ngShow: "kind.value && kind.value !== 'aws'",
|
||||
awRequiredWhen: {variable: 'rackspace_required', init: false },
|
||||
autocomplete: false
|
||||
awRequiredWhen: {
|
||||
variable: 'rackspace_required',
|
||||
init: false
|
||||
},
|
||||
autocomplete: false
|
||||
},
|
||||
"api_key": {
|
||||
label: 'API Key',
|
||||
type: 'password',
|
||||
ngShow: "kind.value == 'rax'",
|
||||
awRequiredWhen: { variable: "rackspace_required", init: false },
|
||||
awRequiredWhen: {
|
||||
variable: "rackspace_required",
|
||||
init: false
|
||||
},
|
||||
autocomplete: false,
|
||||
ask: false,
|
||||
clear: false,
|
||||
apiField: 'passwowrd'
|
||||
},
|
||||
},
|
||||
"password": {
|
||||
label: 'Password',
|
||||
type: 'password',
|
||||
@ -141,7 +162,7 @@ angular.module('CredentialFormDefinition', [])
|
||||
clear: false,
|
||||
associated: 'password_confirm',
|
||||
autocomplete: false
|
||||
},
|
||||
},
|
||||
"password_confirm": {
|
||||
label: 'Confirm Password',
|
||||
type: 'password',
|
||||
@ -151,7 +172,7 @@ angular.module('CredentialFormDefinition', [])
|
||||
awPassMatch: true,
|
||||
associated: 'password',
|
||||
autocomplete: false
|
||||
},
|
||||
},
|
||||
"ssh_password": {
|
||||
label: 'SSH Password',
|
||||
type: 'password',
|
||||
@ -163,7 +184,7 @@ angular.module('CredentialFormDefinition', [])
|
||||
clear: true,
|
||||
associated: 'ssh_password_confirm',
|
||||
autocomplete: false
|
||||
},
|
||||
},
|
||||
"ssh_password_confirm": {
|
||||
label: 'Confirm SSH Password',
|
||||
type: 'password',
|
||||
@ -173,7 +194,7 @@ angular.module('CredentialFormDefinition', [])
|
||||
awPassMatch: true,
|
||||
associated: 'ssh_password',
|
||||
autocomplete: false
|
||||
},
|
||||
},
|
||||
"ssh_key_data": {
|
||||
labelBind: 'sshKeyDataLabel',
|
||||
type: 'textarea',
|
||||
@ -182,7 +203,7 @@ angular.module('CredentialFormDefinition', [])
|
||||
editRequired: false,
|
||||
'class': 'ssh-key-field',
|
||||
rows: 10
|
||||
},
|
||||
},
|
||||
"ssh_key_unlock": {
|
||||
label: 'Key Password',
|
||||
type: 'password',
|
||||
@ -192,9 +213,9 @@ angular.module('CredentialFormDefinition', [])
|
||||
ngChange: "clearPWConfirm('ssh_key_unlock_confirm')",
|
||||
associated: 'ssh_key_unlock_confirm',
|
||||
ask: true,
|
||||
askShow: "kind.value == 'ssh'", //Only allow ask for machine credentials
|
||||
askShow: "kind.value == 'ssh'", //Only allow ask for machine credentials
|
||||
clear: true
|
||||
},
|
||||
},
|
||||
"ssh_key_unlock_confirm": {
|
||||
label: 'Confirm Key Password',
|
||||
type: 'password',
|
||||
@ -203,7 +224,7 @@ angular.module('CredentialFormDefinition', [])
|
||||
editRequired: false,
|
||||
awPassMatch: true,
|
||||
associated: 'ssh_key_unlock'
|
||||
},
|
||||
},
|
||||
"sudo_username": {
|
||||
label: 'Sudo Username',
|
||||
type: 'text',
|
||||
@ -211,7 +232,7 @@ angular.module('CredentialFormDefinition', [])
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
autocomplete: false
|
||||
},
|
||||
},
|
||||
"sudo_password": {
|
||||
label: 'Sudo Password',
|
||||
type: 'password',
|
||||
@ -223,7 +244,7 @@ angular.module('CredentialFormDefinition', [])
|
||||
clear: true,
|
||||
associated: 'sudo_password_confirm',
|
||||
autocomplete: false
|
||||
},
|
||||
},
|
||||
"sudo_password_confirm": {
|
||||
label: 'Confirm Sudo Password',
|
||||
type: 'password',
|
||||
@ -233,24 +254,21 @@ angular.module('CredentialFormDefinition', [])
|
||||
awPassMatch: true,
|
||||
associated: 'sudo_password',
|
||||
autocomplete: false
|
||||
}
|
||||
},
|
||||
|
||||
buttons: { //for now always generates <button> tags
|
||||
save: {
|
||||
label: 'Save',
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
},
|
||||
|
||||
related: { //related colletions (and maybe items?)
|
||||
|
||||
}
|
||||
|
||||
}); //InventoryForm
|
||||
},
|
||||
|
||||
buttons: {
|
||||
save: {
|
||||
label: 'Save',
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
},
|
||||
|
||||
related: {}
|
||||
|
||||
});
|
||||
@ -4,12 +4,11 @@
|
||||
* Groups.js
|
||||
* Form definition for Group model
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
angular.module('GroupFormDefinition', [])
|
||||
.value(
|
||||
'GroupForm', {
|
||||
|
||||
.value('GroupForm', {
|
||||
|
||||
addTitle: 'Create Group',
|
||||
editTitle: 'Edit Group',
|
||||
showTitle: true,
|
||||
@ -18,12 +17,15 @@ angular.module('GroupFormDefinition', [])
|
||||
well: true,
|
||||
formLabelSize: 'col-lg-3',
|
||||
formFieldSize: 'col-lg-9',
|
||||
|
||||
tabs: [
|
||||
{ name: 'properties', label: 'Properties'},
|
||||
{ name: 'source', label: 'Source' }
|
||||
],
|
||||
|
||||
|
||||
tabs: [{
|
||||
name: 'properties',
|
||||
label: 'Properties'
|
||||
}, {
|
||||
name: 'source',
|
||||
label: 'Source'
|
||||
}],
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
label: 'Name',
|
||||
@ -31,19 +33,19 @@ angular.module('GroupFormDefinition', [])
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
tab: 'properties'
|
||||
},
|
||||
description: {
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
tab: 'properties'
|
||||
},
|
||||
},
|
||||
variables: {
|
||||
label: 'Variables',
|
||||
type: 'textarea',
|
||||
addRequired: false,
|
||||
editRequird: false,
|
||||
editRequird: false,
|
||||
rows: 6,
|
||||
'default': '---',
|
||||
dataTitle: 'Group Variables',
|
||||
@ -59,24 +61,27 @@ angular.module('GroupFormDefinition', [])
|
||||
'<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
|
||||
dataContainer: 'body',
|
||||
tab: 'properties'
|
||||
},
|
||||
},
|
||||
source: {
|
||||
label: 'Source',
|
||||
type: 'select',
|
||||
ngOptions: 'source.label for source in source_type_options',
|
||||
ngChange: 'sourceChange()',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
//'default': { label: 'Manual', value: '' },
|
||||
tab: 'source'
|
||||
},
|
||||
},
|
||||
source_path: {
|
||||
label: 'Script Path',
|
||||
ngShow: "source && source.value == 'file'",
|
||||
type: 'text',
|
||||
awRequiredWhen: {variable: "sourcePathRequired", init: "false" },
|
||||
tab: 'source'
|
||||
awRequiredWhen: {
|
||||
variable: "sourcePathRequired",
|
||||
init: "false"
|
||||
},
|
||||
tab: 'source'
|
||||
},
|
||||
credential: {
|
||||
label: 'Cloud Credential',
|
||||
type: 'lookup',
|
||||
@ -84,10 +89,10 @@ angular.module('GroupFormDefinition', [])
|
||||
sourceModel: 'credential',
|
||||
sourceField: 'name',
|
||||
ngClick: 'lookUpCredential()',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
tab: 'source'
|
||||
},
|
||||
},
|
||||
source_regions: {
|
||||
label: 'Regions',
|
||||
type: 'text',
|
||||
@ -102,13 +107,13 @@ angular.module('GroupFormDefinition', [])
|
||||
"</p>",
|
||||
dataContainer: 'body',
|
||||
tab: 'source'
|
||||
},
|
||||
},
|
||||
source_vars: {
|
||||
label: 'Source Variables',
|
||||
ngShow: "source && (source.value == 'file' || source.value == 'ec2')",
|
||||
type: 'textarea',
|
||||
addRequired: false,
|
||||
editRequird: false,
|
||||
editRequird: false,
|
||||
rows: 6,
|
||||
'default': '---',
|
||||
parseTypeName: 'envParseType',
|
||||
@ -126,80 +131,73 @@ angular.module('GroupFormDefinition', [])
|
||||
'<p>View YAML examples at <a href="http://docs.ansible.com/YAMLSyntax.html" target="_blank">docs.ansible.com</a></p>',
|
||||
dataContainer: 'body',
|
||||
tab: 'source'
|
||||
},
|
||||
},
|
||||
checkbox_group: {
|
||||
label: 'Update Options',
|
||||
type: 'checkbox_group',
|
||||
ngShow: "source && (source.value !== '' && source.value !== null)",
|
||||
tab: 'source',
|
||||
|
||||
fields: [
|
||||
{
|
||||
name: 'overwrite',
|
||||
label: 'Overwrite',
|
||||
type: 'checkbox',
|
||||
ngShow: "source.value !== '' && source.value !== null",
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awPopOver: '<p>When checked all child groups and hosts not found on the remote source will be deleted from ' +
|
||||
'the local inventory.</p><p>Unchecked any local child hosts and groups not found on the external source will ' +
|
||||
'remain untouched by the inventory update process.</p>',
|
||||
dataTitle: 'Overwrite',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
},
|
||||
{
|
||||
name: 'overwrite_vars',
|
||||
label: 'Overwrite Variables',
|
||||
type: 'checkbox',
|
||||
ngShow: "source.value !== '' && source.value !== null",
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awPopOver: '<p>If checked, all variables for child groups and hosts will be removed and replaced by those ' +
|
||||
'found on the external source.</p><p>When not checked a merge will be performed, combining local variables with ' +
|
||||
'those found on the external source.</p>',
|
||||
dataTitle: 'Overwrite Variables',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
},
|
||||
{
|
||||
name: 'update_on_launch',
|
||||
label: 'Update on Launch',
|
||||
type: 'checkbox',
|
||||
ngShow: "source.value !== '' && source.value !== null",
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awPopOver: '<p>Each time a job runs using this inventory, refresh the inventory from the selected source before ' +
|
||||
'executing job tasks.</p>',
|
||||
dataTitle: 'Update on Launch',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
fields: [{
|
||||
name: 'overwrite',
|
||||
label: 'Overwrite',
|
||||
type: 'checkbox',
|
||||
ngShow: "source.value !== '' && source.value !== null",
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awPopOver: '<p>When checked all child groups and hosts not found on the remote source will be deleted from ' +
|
||||
'the local inventory.</p><p>Unchecked any local child hosts and groups not found on the external source will ' +
|
||||
'remain untouched by the inventory update process.</p>',
|
||||
dataTitle: 'Overwrite',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
}, {
|
||||
name: 'overwrite_vars',
|
||||
label: 'Overwrite Variables',
|
||||
type: 'checkbox',
|
||||
ngShow: "source.value !== '' && source.value !== null",
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awPopOver: '<p>If checked, all variables for child groups and hosts will be removed and replaced by those ' +
|
||||
'found on the external source.</p><p>When not checked a merge will be performed, combining local variables with ' +
|
||||
'those found on the external source.</p>',
|
||||
dataTitle: 'Overwrite Variables',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
}, {
|
||||
name: 'update_on_launch',
|
||||
label: 'Update on Launch',
|
||||
type: 'checkbox',
|
||||
ngShow: "source.value !== '' && source.value !== null",
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awPopOver: '<p>Each time a job runs using this inventory, refresh the inventory from the selected source before ' +
|
||||
'executing job tasks.</p>',
|
||||
dataTitle: 'Update on Launch',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
}]
|
||||
}
|
||||
},
|
||||
|
||||
buttons: {
|
||||
|
||||
buttons: { //for now always generates <button> tags
|
||||
|
||||
labelClass: 'col-lg-3',
|
||||
controlClass: 'col-lg-5',
|
||||
|
||||
save: {
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
save: {
|
||||
ngClick: 'formSave()',
|
||||
ngDisabled: true
|
||||
},
|
||||
|
||||
related: { //related colletions (and maybe items?)
|
||||
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
related: { }
|
||||
|
||||
});
|
||||
@ -7,14 +7,13 @@
|
||||
*
|
||||
*/
|
||||
angular.module('HostGroupsFormDefinition', [])
|
||||
.value(
|
||||
'HostGroupsForm', {
|
||||
.value('HostGroupsForm', {
|
||||
|
||||
editTitle: 'Host Groups', //Legend in edit mode
|
||||
name: 'host', //Form name attribute
|
||||
well: false, //Wrap the form with TB well
|
||||
editTitle: 'Host Groups',
|
||||
name: 'host',
|
||||
well: false,
|
||||
formLabelSize: 'col-lg-3',
|
||||
formFieldSize: 'col-lg-9',
|
||||
formFieldSize: 'col-lg-9',
|
||||
|
||||
fields: {
|
||||
groups: {
|
||||
@ -26,30 +25,28 @@ angular.module('HostGroupsFormDefinition', [])
|
||||
editRequired: true,
|
||||
awPopOver: "<p>Provide a host name, ip address, or ip address:port. Examples include:</p>" +
|
||||
"<blockquote>myserver.domain.com<br/>" +
|
||||
"127.0.0.1<br />" +
|
||||
"127.0.0.1<br />" +
|
||||
"10.1.0.140:25<br />" +
|
||||
"server.example.com:25" +
|
||||
"</blockquote>",
|
||||
"</blockquote>",
|
||||
dataTitle: 'Host Name',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: '#form-modal .modal-content'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
buttons: { //for now always generates <button> tags
|
||||
save: {
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
save: {
|
||||
ngClick: 'formSave()',
|
||||
ngDisabled: true
|
||||
},
|
||||
|
||||
related: { //related colletions (and maybe items?)
|
||||
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true
|
||||
}
|
||||
},
|
||||
|
||||
related: { }
|
||||
|
||||
}); //UserForm
|
||||
|
||||
|
||||
@ -4,18 +4,17 @@
|
||||
* Hosts.js
|
||||
* Form definition for Host model
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
angular.module('HostFormDefinition', [])
|
||||
.value(
|
||||
'HostForm', {
|
||||
|
||||
addTitle: 'Create Host', //Legend in add mode
|
||||
editTitle: '{{ name }}', //Legend in edit mode
|
||||
name: 'host', //Form name attribute
|
||||
well: false, //Wrap the form with TB well
|
||||
.value('HostForm', {
|
||||
|
||||
addTitle: 'Create Host',
|
||||
editTitle: '{{ name }}',
|
||||
name: 'host',
|
||||
well: false,
|
||||
formLabelSize: 'col-lg-3',
|
||||
formFieldSize: 'col-lg-9',
|
||||
formFieldSize: 'col-lg-9',
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
@ -24,21 +23,21 @@ angular.module('HostFormDefinition', [])
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
awPopOver: "<p>Provide a host name, ip address, or ip address:port. Examples include:</p>" +
|
||||
"<blockquote>myserver.domain.com<br/>" +
|
||||
"127.0.0.1<br />" +
|
||||
"10.1.0.140:25<br />" +
|
||||
"server.example.com:25" +
|
||||
"</blockquote>",
|
||||
"<blockquote>myserver.domain.com<br/>" +
|
||||
"127.0.0.1<br />" +
|
||||
"10.1.0.140:25<br />" +
|
||||
"server.example.com:25" +
|
||||
"</blockquote>",
|
||||
dataTitle: 'Host Name',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: '#form-modal .modal-content'
|
||||
},
|
||||
description: {
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
editRequired: false
|
||||
},
|
||||
},
|
||||
enabled: {
|
||||
label: 'Enabled?',
|
||||
type: 'checkbox',
|
||||
@ -51,12 +50,12 @@ angular.module('HostFormDefinition', [])
|
||||
dataPlacement: 'right',
|
||||
dataContainer: '#form-modal .modal-content',
|
||||
ngDisabled: 'has_inventory_sources == true'
|
||||
},
|
||||
},
|
||||
variables: {
|
||||
label: 'Variables',
|
||||
type: 'textarea',
|
||||
addRequired: false,
|
||||
editRequird: false,
|
||||
editRequird: false,
|
||||
rows: 6,
|
||||
"class": "modal-input-xlarge",
|
||||
"default": "---",
|
||||
@ -70,28 +69,25 @@ angular.module('HostFormDefinition', [])
|
||||
dataTitle: 'Host Variables',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: '#form-modal .modal-content'
|
||||
},
|
||||
},
|
||||
inventory: {
|
||||
type: 'hidden',
|
||||
includeOnEdit: true,
|
||||
includeOnEdit: true,
|
||||
includeOnAdd: true
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
buttons: { //for now always generates <button> tags
|
||||
save: {
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
save: {
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
|
||||
related: { //related colletions (and maybe items?)
|
||||
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
related: {}
|
||||
|
||||
});
|
||||
|
||||
@ -4,12 +4,11 @@
|
||||
* Inventories.js
|
||||
* Form definition for User model
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
angular.module('InventoryFormDefinition', [])
|
||||
.value(
|
||||
'InventoryForm', {
|
||||
|
||||
.value('InventoryForm', {
|
||||
|
||||
addTitle: 'Create Inventory',
|
||||
editTitle: '{{ inventory_name | capitalize }}',
|
||||
name: 'inventory',
|
||||
@ -24,8 +23,8 @@ angular.module('InventoryFormDefinition', [])
|
||||
icon: "icon-comments-alt",
|
||||
mode: 'edit',
|
||||
iconSize: 'large'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
inventory_name: {
|
||||
@ -35,29 +34,32 @@ angular.module('InventoryFormDefinition', [])
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
capitalize: false
|
||||
},
|
||||
inventory_description: {
|
||||
},
|
||||
inventory_description: {
|
||||
realName: 'description',
|
||||
label: 'Description',
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
editRequired: false
|
||||
},
|
||||
},
|
||||
organization: {
|
||||
label: 'Organization',
|
||||
type: 'lookup',
|
||||
sourceModel: 'organization',
|
||||
sourceField: 'name',
|
||||
ngClick: 'lookUpOrganization()',
|
||||
awRequiredWhen: {variable: "organizationrequired", init: "true" }
|
||||
},
|
||||
awRequiredWhen: {
|
||||
variable: "organizationrequired",
|
||||
init: "true"
|
||||
}
|
||||
},
|
||||
inventory_variables: {
|
||||
realName: 'variables',
|
||||
label: 'Variables',
|
||||
type: 'textarea',
|
||||
'class': 'span12',
|
||||
addRequired: false,
|
||||
editRequird: false,
|
||||
editRequird: false,
|
||||
parseTypeName: 'inventoryParseType',
|
||||
rows: 6,
|
||||
"default": "---",
|
||||
@ -71,23 +73,22 @@ angular.module('InventoryFormDefinition', [])
|
||||
dataTitle: 'Inventory Variables',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
buttons: { //for now always generates <button> tags
|
||||
save: {
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
buttons: {
|
||||
save: {
|
||||
ngClick: 'formSave()',
|
||||
ngDisabled: true
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true
|
||||
}
|
||||
},
|
||||
|
||||
related: {
|
||||
|
||||
}
|
||||
|
||||
}); //InventoryForm
|
||||
}
|
||||
|
||||
});
|
||||
@ -1,27 +0,0 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* InventoryGroups.js
|
||||
* Form definition for Groups model
|
||||
*
|
||||
*
|
||||
*/
|
||||
angular.module('InventoryGroupsFormDefinition', [])
|
||||
.value(
|
||||
'InventoryGroupsForm', {
|
||||
|
||||
type: 'groupsview',
|
||||
title: "groupTitle",
|
||||
editTitle: 'Groups',
|
||||
iterator: 'group',
|
||||
|
||||
fields: {
|
||||
},
|
||||
|
||||
actions: {
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
}
|
||||
|
||||
}); //InventoryGroupsForm
|
||||
@ -1,147 +0,0 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* InventoryHosts.js
|
||||
* Form definition for Hosts model
|
||||
*
|
||||
*
|
||||
*/
|
||||
angular.module('InventoryHostsFormDefinition', [])
|
||||
.value(
|
||||
'InventoryHostsForm', {
|
||||
|
||||
type: 'hostsview',
|
||||
title: "groupTitle",
|
||||
editTitle: 'Hosts',
|
||||
iterator: 'host',
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name',
|
||||
ngClick: "editHost(\{\{ host.id \}\}, '\{\{ host.name \}\}')"
|
||||
},
|
||||
active_failures: {
|
||||
label: 'Job Status',
|
||||
ngHref: "\{\{ host.activeFailuresLink \}\}",
|
||||
awToolTip: "\{\{ host.badgeToolTip \}\}",
|
||||
dataPlacement: 'top',
|
||||
badgeNgHref: '\{\{ host.activeFailuresLink \}\}',
|
||||
badgeIcon: "\{\{ 'icon-failures-' + host.has_active_failures \}\}",
|
||||
badgePlacement: 'left',
|
||||
badgeToolTip: "\{\{ host.badgeToolTip \}\}",
|
||||
badgeTipPlacement: 'top',
|
||||
searchable: false,
|
||||
nosort: true
|
||||
},
|
||||
enabled_flag: {
|
||||
label: 'Enabled',
|
||||
badgeIcon: "\{\{ 'icon-enabled-' + host.enabled \}\}",
|
||||
badgePlacement: 'left',
|
||||
badgeToolTip: "\{\{ host.enabledToolTip \}\}",
|
||||
badgeTipPlacement: "top",
|
||||
badgeTipWatch: "host.enabledToolTip",
|
||||
ngClick: "toggle_host_enabled(\{\{ host.id \}\}, \{\{ host.has_inventory_sources \}\})",
|
||||
searchable: false,
|
||||
showValue: false
|
||||
},
|
||||
groups: {
|
||||
label: 'Groups',
|
||||
searchable: true,
|
||||
sourceModel: 'groups',
|
||||
sourceField: 'name',
|
||||
nosort: true
|
||||
},
|
||||
enabled: {
|
||||
label: 'Disabled?',
|
||||
searchSingleValue: true,
|
||||
searchType: 'boolean',
|
||||
searchValue: 'false',
|
||||
searchOnly: true
|
||||
},
|
||||
has_active_failures: {
|
||||
label: 'Has failed jobs?',
|
||||
searchSingleValue: true,
|
||||
searchType: 'boolean',
|
||||
searchValue: 'true',
|
||||
searchOnly: true
|
||||
},
|
||||
has_inventory_sources: {
|
||||
label: 'Has external source?',
|
||||
searchSingleValue: true,
|
||||
searchType: 'boolean',
|
||||
searchValue: 'true',
|
||||
searchOnly: true
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
add: {
|
||||
label: 'Copy',
|
||||
ngClick: "addHost()",
|
||||
ngHide: "hostAddHide",
|
||||
awToolTip: "Copy an existing host to the selected group",
|
||||
dataPlacement: 'top',
|
||||
'class': 'btn-xs btn-success',
|
||||
icon: 'icon-check'
|
||||
},
|
||||
create: {
|
||||
label: 'Create New',
|
||||
ngClick: 'createHost()',
|
||||
ngHide: 'hostCreateHide',
|
||||
awToolTip: 'Create a new host and add it to the selected group',
|
||||
dataPlacement: 'top',
|
||||
'class': 'btn-xs btn-success',
|
||||
icon: 'icon-plus'
|
||||
},
|
||||
help: {
|
||||
dataPlacement: 'top',
|
||||
icon: "icon-question-sign",
|
||||
mode: 'all',
|
||||
'class': 'btn-xs btn-info btn-help',
|
||||
awToolTip: "<div style=\"padding-top:10px; text-align: left;\"><p>Need help getting started?</p>" +
|
||||
"<p>Click here for help with this page</p></div>",
|
||||
iconSize: 'large',
|
||||
ngClick: "showHelp()",
|
||||
id: "hosts-page-help"
|
||||
},
|
||||
stream: {
|
||||
'class': "btn-primary btn-xs activity-btn",
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
dataPlacement: "top",
|
||||
icon: "icon-comments-alt",
|
||||
mode: 'edit',
|
||||
iconSize: 'large'
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
|
||||
ViewJobs: {
|
||||
type: 'DropDown',
|
||||
label: 'Jobs',
|
||||
icon: 'icon-zoom-in',
|
||||
"class": "btn-default btn-xs",
|
||||
options: [
|
||||
{ ngClick: "allJobs(\{\{ host.id \}\})", label: 'All', ngShow: 'host.last_job' },
|
||||
{ ngClick: "allHostSummaries(\{\{ host.id \}\},'\{\{ host.name \}\}', \{\{ inventory_id \}\})", label: 'All summaries',
|
||||
ngShow: 'host.last_job' },
|
||||
{ ngClick: 'viewJobs(\{\{ host.last_job \}\})', label: 'Latest', ngShow: 'host.last_job' },
|
||||
{ ngClick: "viewLastEvents(\{\{ host.id \}\}, '\{\{ host.last_job \}\}', '\{\{ host.name \}\}', " +
|
||||
"'\{\{ host.summary_fields.last_job.name \}\}')", label: 'Latest events', ngShow: 'host.last_job' },
|
||||
{ ngClick: "viewLastSummary(\{\{ host.id \}\}, '\{\{ host.last_job \}\}', '\{\{ host.name \}\}', " +
|
||||
"'\{\{ host.summary_fields.last_job.name \}\}')", label: 'Latest summary', ngShow: 'host.last_job' },
|
||||
{ ngClick: "", label: 'No job data available', ngShow: 'host.last_job == null' }
|
||||
]
|
||||
},
|
||||
|
||||
"delete": {
|
||||
ngClick: "deleteHost(\{\{ host.id \}\},'\{\{ host.name \}\}')",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-xs btn-danger',
|
||||
awToolTip: 'Delete host'
|
||||
}
|
||||
}
|
||||
|
||||
}); //InventoryHostsForm
|
||||
@ -1,57 +0,0 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* InventoryStatus.js
|
||||
* Form definition for Inventory Status -JSON view
|
||||
*
|
||||
*
|
||||
*/
|
||||
angular.module('InventoryStatusDefinition', [])
|
||||
.value(
|
||||
'InventoryStatusForm', {
|
||||
|
||||
name: 'inventory_update',
|
||||
editTitle: 'Inventory Status',
|
||||
well: false,
|
||||
'class': 'horizontal-narrow',
|
||||
|
||||
fields: {
|
||||
license_error: {
|
||||
type: 'alertblock',
|
||||
'class': 'alert-info',
|
||||
alertTxt: 'The invenvtory update process exceeded the available number of licensed hosts. ' +
|
||||
'<strong><a ng-click=\"viewLicense()\" href=\"\">View your license</a></strong> ' +
|
||||
'for more information.',
|
||||
ngShow: 'license_error',
|
||||
closeable: true
|
||||
},
|
||||
created: {
|
||||
label: 'Created',
|
||||
type: 'text',
|
||||
readonly: true
|
||||
},
|
||||
status: {
|
||||
label: 'Status',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
'class': 'nowrap mono-space resizable',
|
||||
rows: '{{ status_rows }}'
|
||||
},
|
||||
result_stdout: {
|
||||
label: 'Std Out',
|
||||
type: 'textarea',
|
||||
ngShow: 'result_stdout',
|
||||
'class': 'nowrap mono-space resizable',
|
||||
readonly: true,
|
||||
rows: '{{ stdout_rows }}'
|
||||
},
|
||||
result_traceback: {
|
||||
label: 'Traceback',
|
||||
type: 'textarea',
|
||||
ngShow: 'result_traceback',
|
||||
'class': 'nowrap mono-space resizable',
|
||||
readonly: true,
|
||||
rows: '{{ traceback_rows }}'
|
||||
}
|
||||
}
|
||||
}); //Form
|
||||
@ -7,10 +7,9 @@
|
||||
*
|
||||
*/
|
||||
angular.module('JobEventDataDefinition', [])
|
||||
.value(
|
||||
'JobEventDataForm', {
|
||||
.value('JobEventDataForm', {
|
||||
|
||||
editTitle: '{{ id }} - {{ event_display }}', //Legend in edit mode
|
||||
editTitle: '{{ id }} - {{ event_display }}',
|
||||
name: 'job_events',
|
||||
well: false,
|
||||
'class': 'horizontal-narrow',
|
||||
@ -22,7 +21,7 @@ angular.module('JobEventDataDefinition', [])
|
||||
readonly: true,
|
||||
rows: 18,
|
||||
'class': 'modal-input-xxlarge'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}); //Form
|
||||
|
||||
144
awx/ui/static/js/forms/JobEvents.js
Normal file
144
awx/ui/static/js/forms/JobEvents.js
Normal file
@ -0,0 +1,144 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* JobEventsForm.js
|
||||
*
|
||||
*/
|
||||
angular.module('JobEventsFormDefinition', [])
|
||||
.value('JobEventsForm', {
|
||||
|
||||
name: 'job_events',
|
||||
well: false,
|
||||
forceListeners: true,
|
||||
|
||||
fields: {
|
||||
status: {
|
||||
labelClass: 'job-{{ status }}',
|
||||
type: 'custom',
|
||||
section: 'Event',
|
||||
control: "<div class=\"job-event-status job-{{ status }}\"><i class=\"fa icon-job-{{ status }}\"></i> {{ status }}</div>"
|
||||
},
|
||||
id: {
|
||||
label: 'ID',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Event',
|
||||
'class': 'span1'
|
||||
},
|
||||
created: {
|
||||
label: 'Created On',
|
||||
type: 'text',
|
||||
section: 'Event',
|
||||
readonly: true
|
||||
},
|
||||
host: {
|
||||
label: 'Host',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Event',
|
||||
ngShow: "host !== ''"
|
||||
},
|
||||
play: {
|
||||
label: 'Play',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Event',
|
||||
ngShow: "play !== ''"
|
||||
},
|
||||
task: {
|
||||
label: 'Task',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Event',
|
||||
ngShow: "task !== ''"
|
||||
},
|
||||
rc: {
|
||||
label: 'Return Code',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Results',
|
||||
'class': 'span1',
|
||||
ngShow: "rc !== ''"
|
||||
},
|
||||
msg: {
|
||||
label: 'Msg',
|
||||
type: 'textarea',
|
||||
readonly: true,
|
||||
section: 'Results',
|
||||
'class': 'nowrap',
|
||||
ngShow: "msg !== ''",
|
||||
rows: 10
|
||||
},
|
||||
stdout: {
|
||||
label: 'Std Out',
|
||||
type: 'textarea',
|
||||
readonly: true,
|
||||
section: 'Results',
|
||||
'class': 'nowrap',
|
||||
ngShow: "stdout !== ''",
|
||||
rows: 10
|
||||
},
|
||||
stderr: {
|
||||
label: 'Std Err',
|
||||
type: 'textarea',
|
||||
readonly: true,
|
||||
section: 'Results',
|
||||
'class': 'nowrap',
|
||||
ngShow: "stderr !== ''",
|
||||
rows: 10
|
||||
},
|
||||
results: {
|
||||
label: 'Results',
|
||||
type: 'textarea',
|
||||
section: 'Results',
|
||||
readonly: true,
|
||||
'class': 'nowrap',
|
||||
ngShow: "results !== ''",
|
||||
rows: 10
|
||||
},
|
||||
start: {
|
||||
label: 'Start',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Timing',
|
||||
ngShow: "start !== ''"
|
||||
},
|
||||
traceback: {
|
||||
label: false,
|
||||
type: 'textarea',
|
||||
readonly: true,
|
||||
section: 'Traceback',
|
||||
'class': 'nowrap',
|
||||
ngShow: "traceback !== ''",
|
||||
rows: 10
|
||||
},
|
||||
end: {
|
||||
label: 'End',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Timing',
|
||||
ngShow: "end !== ''"
|
||||
},
|
||||
delta: {
|
||||
label: 'Elapsed',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Timing',
|
||||
ngShow: "delta !== ''"
|
||||
},
|
||||
module_name: {
|
||||
label: 'Name',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Module',
|
||||
ngShow: "module_name !== ''"
|
||||
},
|
||||
module_args: {
|
||||
label: 'Args',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Module',
|
||||
ngShow: "module_args !== ''"
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -7,8 +7,7 @@
|
||||
*
|
||||
*/
|
||||
angular.module('JobSummaryDefinition', [])
|
||||
.value(
|
||||
'JobSummary', {
|
||||
.value('JobSummary', {
|
||||
|
||||
editTitle: '{{ id }} - {{ name }}',
|
||||
name: 'jobs',
|
||||
@ -21,12 +20,12 @@ angular.module('JobSummaryDefinition', [])
|
||||
control: '<div class=\"job-detail-status\"><span style="padding-right: 15px; font-weight: bold;">Status</span> ' +
|
||||
'<i class=\"fa icon-job-{{ status }}\"></i> {{ status }}</div>',
|
||||
readonly: true
|
||||
},
|
||||
},
|
||||
created: {
|
||||
label: 'Created On',
|
||||
type: 'text',
|
||||
readonly: true
|
||||
},
|
||||
},
|
||||
result_stdout: {
|
||||
label: 'Standard Out',
|
||||
type: 'textarea',
|
||||
@ -35,7 +34,7 @@ angular.module('JobSummaryDefinition', [])
|
||||
rows: '{{ stdout_rows }}',
|
||||
'class': 'nowrap mono-space resizable',
|
||||
ngShow: 'result_stdout != ""'
|
||||
},
|
||||
},
|
||||
result_traceback: {
|
||||
label: 'Traceback',
|
||||
type: 'textarea',
|
||||
@ -44,7 +43,6 @@ angular.module('JobSummaryDefinition', [])
|
||||
rows: '{{ traceback_rows }}',
|
||||
'class': 'nowrap mono-space resizable',
|
||||
ngShow: 'result_traceback != ""'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
@ -7,11 +7,10 @@
|
||||
*
|
||||
*/
|
||||
angular.module('JobTemplateFormDefinition', [])
|
||||
.value(
|
||||
'JobTemplateForm', {
|
||||
.value('JobTemplateForm', {
|
||||
|
||||
addTitle: 'Create Job Templates', //Legend in add mode
|
||||
editTitle: '{{ name }}', //Legend in edit mode
|
||||
addTitle: 'Create Job Templates',
|
||||
editTitle: '{{ name }}',
|
||||
name: 'job_templates',
|
||||
twoColumns: true,
|
||||
well: true,
|
||||
@ -25,8 +24,8 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
icon: "icon-comments-alt",
|
||||
mode: 'edit',
|
||||
iconSize: 'large'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
@ -35,20 +34,20 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
column: 1
|
||||
},
|
||||
description: {
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
column: 1
|
||||
},
|
||||
},
|
||||
job_type: {
|
||||
label: 'Job Type',
|
||||
type: 'select',
|
||||
ngOptions: 'type.label for type in job_type_options',
|
||||
"default": 0,
|
||||
addRequired: true,
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
column: 1,
|
||||
awPopOver: "<p>When this template is submitted as a job, setting the type to <em>run</em> will execute the playbook, running tasks " +
|
||||
@ -57,7 +56,7 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
dataTitle: 'Job Type',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
inventory: {
|
||||
label: 'Inventory',
|
||||
type: 'lookup',
|
||||
@ -70,7 +69,7 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
dataTitle: 'Inventory',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
project: {
|
||||
label: 'Project',
|
||||
type: 'lookup',
|
||||
@ -83,7 +82,7 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
dataTitle: 'Project',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
playbook: {
|
||||
label: 'Playbook',
|
||||
type:'select',
|
||||
@ -95,29 +94,29 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
dataTitle: 'Playbook',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
credential: {
|
||||
label: 'Machine Credential',
|
||||
type: 'lookup',
|
||||
sourceModel: 'credential',
|
||||
sourceField: 'name',
|
||||
ngClick: 'lookUpCredential()',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
column: 1,
|
||||
awPopOver: "<p>Select the credential you want the job to use when accessing the remote hosts. Choose the credential containing " +
|
||||
awPopOver: "<p>Select the credential you want the job to use when accessing the remote hosts. Choose the credential containing " +
|
||||
" the username and SSH key or password that Ansbile will need to log into the remote hosts.</p>",
|
||||
dataTitle: 'Credential',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
cloud_credential: {
|
||||
label: 'Cloud Credential',
|
||||
type: 'lookup',
|
||||
sourceModel: 'cloud_credential',
|
||||
sourceField: 'name',
|
||||
ngClick: 'lookUpCloudcredential()',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
column: 1,
|
||||
awPopOver: "<p>Selecting an optional cloud credential in the job template will pass along the access credentials to the " +
|
||||
@ -125,16 +124,16 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
dataTitle: 'Cloud Credential',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
forks: {
|
||||
label: 'Forks',
|
||||
id: 'forks-number',
|
||||
type: 'number',
|
||||
type: 'number',
|
||||
integer: true,
|
||||
min: 0,
|
||||
spinner: true,
|
||||
spinner: true,
|
||||
"default": '0',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
'class': "input-small",
|
||||
column: 1,
|
||||
@ -144,11 +143,11 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
dataTitle: 'Forks',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
limit: {
|
||||
label: 'Limit',
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
column: 1,
|
||||
awPopOver: "<p>Provide a host pattern to further constrain the list of hosts that will be managed or affected by the playbook. " +
|
||||
@ -157,26 +156,26 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
dataTitle: 'Limit',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
verbosity: {
|
||||
label: 'Verbosity',
|
||||
type: 'select',
|
||||
ngOptions: 'v.label for v in verbosity_options',
|
||||
"default": 0,
|
||||
addRequired: true,
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
column: 1,
|
||||
awPopOver: "<p>Control the level of output ansible will produce as the playbook executes.</p>",
|
||||
dataTitle: 'Verbosity',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
variables: {
|
||||
label: 'Extra Variables',
|
||||
type: 'textarea',
|
||||
rows: 6,
|
||||
"class": 'span12',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
"default": "---",
|
||||
column: 2,
|
||||
@ -189,13 +188,13 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
dataTitle: 'Extra Variables',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
job_tags: {
|
||||
label: 'Job Tags',
|
||||
type: 'textarea',
|
||||
rows: 1,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
type: 'textarea',
|
||||
rows: 1,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
'class': 'span12',
|
||||
column: 2,
|
||||
awPopOver: "<p>Provide a comma separated list of tags.</p>\n" +
|
||||
@ -203,26 +202,25 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
"<p>For example, you might have a task consisiting of a long list of actions. Tag values can be assigned to each action. " +
|
||||
"Suppose the actions have been assigned tag values of "configuration", "packages" and "install".</p>" +
|
||||
"<p>If you just want to run the "configuration" and "packages" actions, you would enter the following here " +
|
||||
"in the Job Tags field:<\p>\n" +
|
||||
"<blockquote>configuration,packages</blockquote>\n",
|
||||
"in the Job Tags field:</p>\n<blockquote>configuration,packages</blockquote>\n",
|
||||
dataTitle: "Job Tags",
|
||||
dataPlacement: "right",
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
allow_callbacks: {
|
||||
label: 'Allow Callbacks',
|
||||
type: 'checkbox',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequird: false,
|
||||
trueValue: 'true',
|
||||
falseValue: 'false',
|
||||
ngChange: "toggleCallback('host_config_key')",
|
||||
column: 2,
|
||||
awPopOver: "<p>Create a callback URL a host can use to contact Tower and request a configuration update " +
|
||||
awPopOver: "<p>Create a callback URL a host can use to contact Tower and request a configuration update " +
|
||||
"using the job template. The URL will look like the following:</p>\n" +
|
||||
"<p class=\"code-breakable\">http://your.server.com:999/api/v1/job_templates/1/callback/</p>" +
|
||||
"<p>The request from the host must be a POST. Here is an example using curl:</p>\n" +
|
||||
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
|
||||
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
|
||||
"http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n" +
|
||||
"<p>Note the requesting host must be defined in your inventory. If ansible fails to locate the host either by name or IP address " +
|
||||
"in one of your defined inventories, the request will be denied.</p>" +
|
||||
@ -230,11 +228,11 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
dataPlacement: 'right',
|
||||
dataTitle: 'Callback URL',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
callback_url: {
|
||||
label: 'Callback URL',
|
||||
label: 'Callback URL',
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
readonly: true,
|
||||
column: 2,
|
||||
@ -242,7 +240,7 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
'class': 'span12',
|
||||
awPopOver: "<p>Using this URL a host can contact Tower and request a configuration update using the job " +
|
||||
"template. The request from the host must be a POST. Here is an example using curl:</p>\n" +
|
||||
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
|
||||
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
|
||||
"http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n" +
|
||||
"<p>Note the requesting host must be defined in your inventory. If ansible fails to locate the host either by name or IP address " +
|
||||
"in one of your defined inventories, the request will be denied.</p>" +
|
||||
@ -250,7 +248,7 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
dataPlacement: 'right',
|
||||
dataTitle: 'Callback URL',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
host_config_key: {
|
||||
label: 'Host Config Key',
|
||||
type: 'text',
|
||||
@ -259,25 +257,25 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
column: 2,
|
||||
awPopOver: "<p>When contacting the Tower server using the callback URL, the calling host must authenticate by including " +
|
||||
"this key in the POST data of the request. Here's an example using curl:</p>\n" +
|
||||
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
|
||||
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
|
||||
"http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n",
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
buttons: { //for now always generates <button> tags
|
||||
save: {
|
||||
save: {
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
reset: {
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
related: { //related colletions (and maybe items?)
|
||||
related: {
|
||||
|
||||
jobs: {
|
||||
type: 'collection',
|
||||
@ -295,54 +293,55 @@ angular.module('JobTemplateFormDefinition', [])
|
||||
awToolTip: "Reset the search filter",
|
||||
ngClick: "resetSearch('job')",
|
||||
iconSize: 'large'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
id: {
|
||||
label: 'Job ID',
|
||||
key: true,
|
||||
desc: true,
|
||||
searchType: 'int'
|
||||
},
|
||||
searchType: 'int'
|
||||
},
|
||||
created: {
|
||||
label: 'Date',
|
||||
link: false,
|
||||
searchable: false
|
||||
},
|
||||
},
|
||||
status: {
|
||||
label: 'Status',
|
||||
"class": 'job-\{\{ job.status \}\}',
|
||||
"class": 'job-{{ job.status }}',
|
||||
searchType: 'select',
|
||||
linkTo: "\{\{ job.statusLinkTo \}\}",
|
||||
linkTo: "{{}} job.statusLinkTo }}",
|
||||
searchOptions: [
|
||||
{ name: "new", value: "new" },
|
||||
{ name: "waiting", value: "waiting" },
|
||||
{ name: "pending", value: "pending" },
|
||||
{ name: "running", value: "running" },
|
||||
{ name: "running", value: "running" },
|
||||
{ name: "successful", value: "successful" },
|
||||
{ name: "error", value: "error" },
|
||||
{ name: "failed", value: "failed" },
|
||||
{ name: "canceled", value: "canceled" } ],
|
||||
badgeIcon: 'fa icon-job-\{\{ job.status \}\}',
|
||||
{ name: "canceled", value: "canceled" }
|
||||
],
|
||||
badgeIcon: 'fa icon-job-{{ job.status }}',
|
||||
badgePlacement: 'left',
|
||||
badgeToolTip: "\{\{ job.statusBadgeToolTip \}\}",
|
||||
badgeToolTip: "{{ job.statusBadgeToolTip }}",
|
||||
badgeTipPlacement: 'top',
|
||||
badgeNgHref: "\{\{ job.statusLinkTo \}\}",
|
||||
awToolTip: "\{\{ job.statusBadgeToolTip \}\}",
|
||||
badgeNgHref: "{{ job.statusLinkTo }}",
|
||||
awToolTip: "{{ job.statusBadgeToolTip }}",
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'View',
|
||||
ngClick: "edit('jobs', \{\{ job.id \}\}, '\{\{ job.name \}\}')",
|
||||
ngClick: "edit('jobs', job.id, job.name)",
|
||||
icon: 'icon-zoom-in'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}); //InventoryForm
|
||||
|
||||
|
||||
@ -7,9 +7,8 @@
|
||||
* @dict
|
||||
*/
|
||||
angular.module('JobFormDefinition', [])
|
||||
.value(
|
||||
'JobForm', {
|
||||
|
||||
.value('JobForm', {
|
||||
|
||||
addTitle: 'Create Job',
|
||||
editTitle: '{{ id }} - {{ name }}',
|
||||
name: 'jobs',
|
||||
@ -26,19 +25,19 @@ angular.module('JobFormDefinition', [])
|
||||
icon: 'icon-zoom-in',
|
||||
active: true,
|
||||
ngShow: "job_id !== null"
|
||||
},
|
||||
},
|
||||
events: {
|
||||
href: "/#/jobs/{{ job_id }}/job_events",
|
||||
label: 'Events',
|
||||
icon: 'icon-list-ul'
|
||||
},
|
||||
hosts: {
|
||||
},
|
||||
hosts: {
|
||||
href: "/#/jobs/{{ job_id }}/job_host_summaries",
|
||||
label: 'Host Summary',
|
||||
icon: 'icon-laptop'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
label: 'Job Template',
|
||||
@ -47,20 +46,20 @@ angular.module('JobFormDefinition', [])
|
||||
editRequired: false,
|
||||
readonly: true,
|
||||
column: 1
|
||||
},
|
||||
description: {
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
column: 1
|
||||
},
|
||||
},
|
||||
job_type: {
|
||||
label: 'Job Type',
|
||||
type: 'select',
|
||||
ngOptions: 'type.label for type in job_type_options',
|
||||
"default": 'run',
|
||||
addRequired: true,
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
awPopOver: "<p>When this template is submitted as a job, setting the type to <em>run</em> will execute the playbook, running tasks " +
|
||||
" on the selected hosts.</p> <p>Setting the type to <em>check</em> will not execute the playbook. Instead, ansible will check playbook " +
|
||||
@ -69,7 +68,7 @@ angular.module('JobFormDefinition', [])
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body',
|
||||
column: 1
|
||||
},
|
||||
},
|
||||
inventory: {
|
||||
label: 'Inventory',
|
||||
type: 'lookup',
|
||||
@ -83,7 +82,7 @@ angular.module('JobFormDefinition', [])
|
||||
dataTitle: 'Inventory',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
project: {
|
||||
label: 'Project',
|
||||
type: 'lookup',
|
||||
@ -97,42 +96,42 @@ angular.module('JobFormDefinition', [])
|
||||
dataTitle: 'Project',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
playbook: {
|
||||
label: 'Playbook',
|
||||
type:'select',
|
||||
type: 'select',
|
||||
ngOptions: 'book for book in playbook_options',
|
||||
id: 'playbook-select',
|
||||
addRequired: true,
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
column: 1,
|
||||
awPopOver: "<p>Select the playbook to be executed by this job.</p>",
|
||||
dataTitle: 'Playbook',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
credential: { // FIXME: Lookup only credentials with kind=ssh
|
||||
label: 'Credential',
|
||||
type: 'lookup',
|
||||
sourceModel: 'credential',
|
||||
sourceField: 'name',
|
||||
ngClick: 'lookUpCredential()',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
column: 1,
|
||||
awPopOver: "<p>Select the credential you want the job to use when accessing the remote hosts. Choose the credential containing " +
|
||||
" the username and SSH key or password that Ansbile will need to log into the remote hosts.</p>",
|
||||
awPopOver: "<p>Select the credential you want the job to use when accessing the remote hosts. Choose the credential containing " +
|
||||
" the username and SSH key or password that Ansbile will need to log into the remote hosts.</p>",
|
||||
dataTitle: 'Credential',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
cloud_credential: { // FIXME: Lookup only credentials with kind=aws/rax
|
||||
label: 'Cloud Credential',
|
||||
type: 'lookup',
|
||||
sourceModel: 'cloud_credential',
|
||||
sourceField: 'name',
|
||||
ngClick: 'lookUpCredential()',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
column: 1,
|
||||
awPopOver: "<p>Selecting an optional cloud credential in the job template will pass along the access credentials to the " +
|
||||
@ -140,17 +139,17 @@ angular.module('JobFormDefinition', [])
|
||||
dataTitle: 'Cloud Credential',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: "body"
|
||||
},
|
||||
},
|
||||
forks: {
|
||||
label: 'Forks',
|
||||
id: 'forks-number',
|
||||
type: 'number',
|
||||
type: 'number',
|
||||
integer: true,
|
||||
min: 0,
|
||||
spinner: true,
|
||||
spinner: true,
|
||||
"class": 'input-small',
|
||||
"default": '0',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
column: 1,
|
||||
disabled: true,
|
||||
@ -158,43 +157,43 @@ angular.module('JobFormDefinition', [])
|
||||
dataContainer: 'body',
|
||||
dataTitle: 'Forks',
|
||||
dataPlacement: 'right'
|
||||
},
|
||||
},
|
||||
limit: {
|
||||
label: 'Limit',
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
column: 1,
|
||||
awPopOver: "<p>Provide a host pattern to further constrain the list of hosts that will be managed or affected by the playbook. " +
|
||||
"Multiple patterns can be separated by ; : or ,</p><p>For more information and examples see the " +
|
||||
"<a href=\"http://ansible.cc/docs/patterns.html#selecting-targets\" target=\"_blank\">Selecting Targets section</a> under Inventory and Patterns " +
|
||||
"<a href=\"http://ansible.cc/docs/patterns.html#selecting-targets\" target=\"_blank\">Selecting Targets section</a> under Inventory and Patterns " +
|
||||
" in the Ansible documentation.</p>",
|
||||
dataContainer: 'body',
|
||||
dataTitle: 'Limit',
|
||||
dataPlacement: 'right'
|
||||
},
|
||||
},
|
||||
verbosity: {
|
||||
label: 'Verbosity',
|
||||
type: 'select',
|
||||
ngOptions: 'v.label for v in verbosity_options',
|
||||
"default": 0,
|
||||
addRequired: true,
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
column: 1,
|
||||
awPopOver: "<p>Control the level of output ansible will produce as the playbook executes.</p>",
|
||||
dataTitle: 'Verbosity',
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body'
|
||||
},
|
||||
},
|
||||
variables: {
|
||||
label: 'Extra Variables',
|
||||
type: 'textarea',
|
||||
rows: 6,
|
||||
"class": 'span12',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
column: 2,
|
||||
awPopOver: "<p>Pass extra command line variables to the playbook. This is the -e or --extra-vars command line parameter " +
|
||||
awPopOver: "<p>Pass extra command line variables to the playbook. This is the -e or --extra-vars command line parameter " +
|
||||
"for ansible-playbook. Provide key/value pairs using either YAML or JSON.</p>" +
|
||||
"JSON:<br />\n" +
|
||||
"<blockquote>{<br />\"somevar\": \"somevalue\",<br />\"password\": \"magic\"<br /> }</blockquote>\n" +
|
||||
@ -203,13 +202,13 @@ angular.module('JobFormDefinition', [])
|
||||
dataTitle: 'Extra Variables',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right'
|
||||
},
|
||||
},
|
||||
job_tags: {
|
||||
label: 'Job Tags',
|
||||
type: 'textarea',
|
||||
rows: 1,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
type: 'textarea',
|
||||
rows: 1,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
'class': 'span12',
|
||||
column: 2,
|
||||
awPopOver: "<p>Provide a comma separated list of tags.</p>\n" +
|
||||
@ -217,27 +216,27 @@ angular.module('JobFormDefinition', [])
|
||||
"<p>For example, you might have a task consisiting of a long list of actions. Tag values can be assigned to each action. " +
|
||||
"Suppose the actions have been assigned tag values of "configuration", "packages" and "install".</p>" +
|
||||
"<p>If you just want to run the "configuration" and "packages" actions, you would enter the following here " +
|
||||
"in the Job Tags field:<\p>\n" +
|
||||
"in the Job Tags field:</p>\n" +
|
||||
"<blockquote>configuration,packages</blockquote>\n",
|
||||
dataTitle: "Job Tags",
|
||||
dataContainer: 'body',
|
||||
dataPlacement: "right"
|
||||
},
|
||||
},
|
||||
allow_callbacks: {
|
||||
label: 'Allow Callbacks',
|
||||
type: 'checkbox',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequird: false,
|
||||
trueValue: 'true',
|
||||
falseValue: 'false',
|
||||
ngChange: "toggleCallback('host_config_key')",
|
||||
"class": "span12",
|
||||
column: 2,
|
||||
awPopOver: "<p>Create a callback URL a host can use to contact Tower and request a configuration update " +
|
||||
awPopOver: "<p>Create a callback URL a host can use to contact Tower and request a configuration update " +
|
||||
"using the job template. The URL will look like the following:</p>\n" +
|
||||
"<p class=\"code-breakable\">http://your.server.com:999/api/v1/job_templates/1/callback/</p>" +
|
||||
"<p>The request from the host must be a POST. Here is an example using curl:</p>\n" +
|
||||
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
|
||||
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
|
||||
"http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n" +
|
||||
"<p>Note the requesting host must be defined in your inventory. If ansible fails to locate the host either by name or IP address " +
|
||||
"in one of your defined inventories, the request will be denied.</p>" +
|
||||
@ -245,11 +244,11 @@ angular.module('JobFormDefinition', [])
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body',
|
||||
dataTitle: 'Callback URL'
|
||||
},
|
||||
},
|
||||
callback_url: {
|
||||
label: 'Callback URL',
|
||||
label: 'Callback URL',
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
readonly: true,
|
||||
column: 2,
|
||||
@ -257,7 +256,7 @@ angular.module('JobFormDefinition', [])
|
||||
'class': 'span12',
|
||||
awPopOver: "<p>Using this URL a host can contact Tower and request a configuration update using the job " +
|
||||
"template. The request from the host must be a POST. Here is an example using curl:</p>\n" +
|
||||
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
|
||||
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
|
||||
"http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n" +
|
||||
"<p>Note the requesting host must be defined in your inventory. If ansible fails to locate the host either by name or IP address " +
|
||||
"in one of your defined inventories, the request will be denied.</p>" +
|
||||
@ -265,7 +264,7 @@ angular.module('JobFormDefinition', [])
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body',
|
||||
dataTitle: 'Callback URL'
|
||||
},
|
||||
},
|
||||
host_config_key: {
|
||||
label: 'Host Config Key',
|
||||
type: 'text',
|
||||
@ -274,64 +273,65 @@ angular.module('JobFormDefinition', [])
|
||||
column: 2,
|
||||
awPopOver: "<p>When contacting Tower using the callback URL, the calling host must authenticate by including " +
|
||||
"this key in the POST data of the request. Here's an example using curl:</p>\n" +
|
||||
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
|
||||
"<p class=\"code-breakable\">curl --data \"host_config_key=5a8ec154832b780b9bdef1061764ae5a\" " +
|
||||
"http://your.server.com:999/api/v1/job_templates/1/callback/</p>\n",
|
||||
dataPlacement: 'right',
|
||||
dataContainer: 'body'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
buttons: { //for now always generates <button> tags
|
||||
save: {
|
||||
label: 'Save',
|
||||
buttons: {
|
||||
save: {
|
||||
label: 'Save',
|
||||
icon: 'icon-ok',
|
||||
"class": 'btn-success',
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formSave()',
|
||||
ngDisabled: true
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
label: 'Reset',
|
||||
icon: 'icon-undo',
|
||||
'class': 'btn btn-default',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
},
|
||||
ngDisabled: true
|
||||
}
|
||||
},
|
||||
|
||||
statusFields: {
|
||||
status: {
|
||||
//label: 'Job Status',
|
||||
type: 'custom',
|
||||
control: '<div class=\"job-detail-status\"><span style="padding-right: 15px; font-weight: bold;">Status</span> <i class=\"fa icon-job-\{\{ status \}\}\"></i> \{\{ status \}\}</div>',
|
||||
control: "<div class=\"job-detail-status\"><span style=\"padding-right: 15px; font-weight: bold;\">Status</span> " +
|
||||
"<i class=\"fa icon-job-{{ status }}\"></i> {{ status }}</div>",
|
||||
readonly: true
|
||||
},
|
||||
},
|
||||
created: {
|
||||
label: 'Created On',
|
||||
type: 'text',
|
||||
readonly: true
|
||||
},
|
||||
},
|
||||
result_stdout: {
|
||||
label: 'Standard Out',
|
||||
label: 'Standard Out',
|
||||
type: 'textarea',
|
||||
readonly: true,
|
||||
xtraWide: true,
|
||||
rows: "\{\{ stdout_rows \}\}",
|
||||
rows: "{{ stdout_rows }}",
|
||||
"class": 'nowrap mono-space',
|
||||
ngShow: "result_stdout != ''"
|
||||
},
|
||||
},
|
||||
result_traceback: {
|
||||
label: 'Traceback',
|
||||
type: 'textarea',
|
||||
xtraWide: true,
|
||||
readonly: true,
|
||||
rows: "\{\{ traceback_rows \}\}",
|
||||
rows: "{{ traceback_rows }}",
|
||||
"class": 'nowrap mono-space',
|
||||
ngShow: "result_traceback != ''"
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
statusActions: {
|
||||
refresh: {
|
||||
refresh: {
|
||||
dataPlacement: 'top',
|
||||
icon: "icon-refresh",
|
||||
iconSize: 'large',
|
||||
@ -340,8 +340,7 @@ angular.module('JobFormDefinition', [])
|
||||
'class': 'btn-xs btn-primary',
|
||||
awToolTip: "Refresh the page",
|
||||
ngClick: "refresh()"
|
||||
}
|
||||
}
|
||||
|
||||
}); //Form
|
||||
}
|
||||
|
||||
});
|
||||
84
awx/ui/static/js/forms/LicenseForm.js
Normal file
84
awx/ui/static/js/forms/LicenseForm.js
Normal file
@ -0,0 +1,84 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* LicenseForm.js
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('LicenseFormDefinition', [])
|
||||
.value('LicenseForm', {
|
||||
|
||||
name: 'license',
|
||||
well: false,
|
||||
forceListeners: true,
|
||||
|
||||
fields: {
|
||||
license_status: {
|
||||
type: 'custom',
|
||||
control: "<div class=\"license-status\" ng-class=\"status_color\"><i class=\"fa fa-circle\"></i> " +
|
||||
"{{ license_status }}</span></div>",
|
||||
readonly: true,
|
||||
section: 'License'
|
||||
},
|
||||
license_key: {
|
||||
label: 'Key',
|
||||
type: 'textarea',
|
||||
'class': 'modal-input-xlarge',
|
||||
readonly: true,
|
||||
section: 'License'
|
||||
},
|
||||
license_date: {
|
||||
label: 'Expires On',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'License'
|
||||
},
|
||||
time_remaining: {
|
||||
label: 'Time Left',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'License'
|
||||
},
|
||||
available_instances: {
|
||||
label: 'Available',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Managed Hosts'
|
||||
},
|
||||
current_instances: {
|
||||
label: 'Used',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Managed Hosts'
|
||||
},
|
||||
free_instances: {
|
||||
label: 'Remaining',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Managed Hosts',
|
||||
controlNGClass: 'free_instances_class',
|
||||
labelNGClass: 'free_instances_class'
|
||||
},
|
||||
company_name: {
|
||||
label: 'Company',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Contact Info'
|
||||
},
|
||||
contact_name: {
|
||||
label: 'Contact',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Contact Info'
|
||||
},
|
||||
contact_email: {
|
||||
label: 'Contact Email',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Contact Info'
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -4,16 +4,15 @@
|
||||
* Organization.js
|
||||
* Form definition for Organization model
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
angular.module('OrganizationFormDefinition', [])
|
||||
.value(
|
||||
'OrganizationForm', {
|
||||
|
||||
addTitle: 'Create Organization', //Title in add mode
|
||||
editTitle: '{{ name }}', //Title in edit mode
|
||||
name: 'organization', //entity or model name in singular form
|
||||
well: true, //Wrap the form with TB well/
|
||||
.value('OrganizationForm', {
|
||||
|
||||
addTitle: 'Create Organization', //Title in add mode
|
||||
editTitle: '{{ name }}', //Title in edit mode
|
||||
name: 'organization', //entity or model name in singular form
|
||||
well: true,
|
||||
|
||||
actions: {
|
||||
stream: {
|
||||
@ -24,8 +23,8 @@ angular.module('OrganizationFormDefinition', [])
|
||||
icon: "icon-comments-alt",
|
||||
mode: 'edit',
|
||||
iconSize: 'large'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
@ -34,120 +33,118 @@ angular.module('OrganizationFormDefinition', [])
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
capitalize: false
|
||||
},
|
||||
description: {
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
editRequired: false
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
buttons: { //for now always generates <button> tags
|
||||
save: {
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
reset: {
|
||||
buttons: { //for now always generates <button> tags
|
||||
save: {
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
},
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
},
|
||||
|
||||
related: { //related colletions (and maybe items?)
|
||||
related: {
|
||||
|
||||
users: {
|
||||
users: {
|
||||
type: 'collection',
|
||||
title: 'Users',
|
||||
iterator: 'user',
|
||||
open: false,
|
||||
|
||||
actions: {
|
||||
|
||||
actions: {
|
||||
add: {
|
||||
ngClick: "add('users')",
|
||||
label: 'Add',
|
||||
icon: 'icon-plus',
|
||||
awToolTip: 'Add a new user'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
username: {
|
||||
key: true,
|
||||
label: 'Username'
|
||||
},
|
||||
},
|
||||
first_name: {
|
||||
label: 'First Name'
|
||||
},
|
||||
},
|
||||
last_name: {
|
||||
label: 'Last Name'
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "edit('users', \{\{ user.id \}\}, '\{\{ user.username \}\}')",
|
||||
icon: 'icon-edit',
|
||||
'class': 'btn-default',
|
||||
awToolTip: 'Edit user'
|
||||
},
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "delete('users', \{\{ user.id \}\}, '\{\{ user.username \}\}', 'users')",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-danger',
|
||||
awToolTip: 'Remove user'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
admins: { // Assumes a plural name (e.g. things)
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "edit('users', user.id, user.username)",
|
||||
icon: 'icon-edit',
|
||||
'class': 'btn-default',
|
||||
awToolTip: 'Edit user'
|
||||
},
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "delete('users', user.id, user.username, 'users')",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-danger',
|
||||
awToolTip: 'Remove user'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
admins: { // Assumes a plural name (e.g. things)
|
||||
type: 'collection',
|
||||
title: 'Administrators',
|
||||
iterator: 'admin', // Singular form of name (e.g. thing)
|
||||
open: false, // Open accordion on load?
|
||||
iterator: 'admin', // Singular form of name (e.g. thing)
|
||||
open: false, // Open accordion on load?
|
||||
base: '/users',
|
||||
actions: { // Actions displayed top right of list
|
||||
actions: { // Actions displayed top right of list
|
||||
add: {
|
||||
ngClick: "add('admins')",
|
||||
icon: 'icon-plus',
|
||||
label: 'Add',
|
||||
awToolTip: 'Add new administrator'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
fields: {
|
||||
username: {
|
||||
key: true,
|
||||
label: 'Username'
|
||||
},
|
||||
},
|
||||
first_name: {
|
||||
label: 'First Name'
|
||||
},
|
||||
},
|
||||
last_name: {
|
||||
label: 'Last Name'
|
||||
}
|
||||
},
|
||||
fieldActions: { // Actions available on each row
|
||||
}
|
||||
},
|
||||
fieldActions: { // Actions available on each row
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "edit('users', \{\{ admin.id \}\}, '\{\{ admin.username \}\}')",
|
||||
ngClick: "edit('users', admin.id, admin.username)",
|
||||
icon: 'icon-edit',
|
||||
awToolTip: 'Edit administrator',
|
||||
'class': 'btn-default'
|
||||
},
|
||||
},
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "delete('admins', \{\{ admin.id \}\}, '\{\{ admin.username \}\}', 'administrators')",
|
||||
ngClick: "delete('admins', admin.id, admin.username, 'administrators')",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-danger',
|
||||
awToolTip: 'Remove administrator'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}); //OrganizationForm
|
||||
}
|
||||
|
||||
|
||||
}); //OrganizationForm
|
||||
|
||||
@ -5,60 +5,63 @@
|
||||
*
|
||||
* Form definition for Projects model
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
angular.module('PermissionFormDefinition', [])
|
||||
.value(
|
||||
'PermissionsForm', {
|
||||
|
||||
addTitle: 'Add Permission', //Title in add mode
|
||||
editTitle: '{{ name }}', //Title in edit mode
|
||||
name: 'permission', //entity or model name in singular form
|
||||
well: true, //Wrap the form with TB well
|
||||
forceListeners: true,
|
||||
.value('PermissionsForm', {
|
||||
|
||||
addTitle: 'Add Permission', //Title in add mode
|
||||
editTitle: '{{ name }}', //Title in edit mode
|
||||
name: 'permission', //entity or model name in singular form
|
||||
well: true, //Wrap the form with TB well
|
||||
forceListeners: true,
|
||||
|
||||
stream: {
|
||||
'class': "btn-primary btn-xs activity-btn",
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
dataPlacement: "top",
|
||||
icon: "icon-comments-alt",
|
||||
mode: 'edit',
|
||||
iconSize: 'large'
|
||||
},
|
||||
|
||||
'class': "btn-primary btn-xs activity-btn",
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
dataPlacement: "top",
|
||||
icon: "icon-comments-alt",
|
||||
mode: 'edit',
|
||||
iconSize: 'large'
|
||||
},
|
||||
|
||||
fields: {
|
||||
category: {
|
||||
label: 'Permission Type',
|
||||
labelClass: 'prepend-asterisk',
|
||||
type: 'radio_group',
|
||||
options: [
|
||||
{ label: 'Inventory', value: 'Inventory', selected: true },
|
||||
{ label: 'Deployment', value: 'Deploy'}
|
||||
],
|
||||
options: [{
|
||||
label: 'Inventory',
|
||||
value: 'Inventory',
|
||||
selected: true
|
||||
}, {
|
||||
label: 'Deployment',
|
||||
value: 'Deploy'
|
||||
}],
|
||||
ngChange: 'selectCategory()'
|
||||
},
|
||||
},
|
||||
name: {
|
||||
label: 'Name',
|
||||
type: 'text',
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
capitalize: false
|
||||
},
|
||||
description: {
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
editRequired: false
|
||||
},
|
||||
},
|
||||
user: {
|
||||
label: 'User',
|
||||
label: 'User',
|
||||
type: 'hidden'
|
||||
},
|
||||
},
|
||||
team: {
|
||||
label: 'Team',
|
||||
type: 'hidden'
|
||||
},
|
||||
},
|
||||
project: {
|
||||
label: 'Project',
|
||||
type: 'lookup',
|
||||
@ -66,44 +69,65 @@ angular.module('PermissionFormDefinition', [])
|
||||
sourceField: 'name',
|
||||
ngShow: "category == 'Deploy'",
|
||||
ngClick: 'lookUpProject()',
|
||||
awRequiredWhen: { variable: "projectrequired", init: "false" }
|
||||
},
|
||||
awRequiredWhen: {
|
||||
variable: "projectrequired",
|
||||
init: "false"
|
||||
}
|
||||
},
|
||||
inventory: {
|
||||
label: 'Inventory',
|
||||
type: 'lookup',
|
||||
sourceModel: 'inventory',
|
||||
sourceField: 'name',
|
||||
ngClick: 'lookUpInventory()',
|
||||
awRequiredWhen: {variable: "inventoryrequired", init: "true" }
|
||||
},
|
||||
awRequiredWhen: {
|
||||
variable: "inventoryrequired",
|
||||
init: "true"
|
||||
}
|
||||
},
|
||||
permission_type: {
|
||||
label: 'Permission',
|
||||
labelClass: 'prepend-asterisk',
|
||||
type: 'radio_group',
|
||||
options: [
|
||||
{label: 'Read', value: 'read', ngShow: "category == 'Inventory'" },
|
||||
{label: 'Write', value: 'write', ngShow: "category == 'Inventory'" },
|
||||
{label: 'Admin', value: 'admin', ngShow: "category == 'Inventory'" },
|
||||
{label: 'Run', value: 'run', ngShow: "category == 'Deploy'" },
|
||||
{label: 'Check', value: 'check', ngShow: "category == 'Deploy'" }
|
||||
],
|
||||
helpCollapse: [{ hdr: 'Permission', ngBind: 'permissionTypeHelp' }]
|
||||
}
|
||||
},
|
||||
|
||||
buttons: { //for now always generates <button> tags
|
||||
save: {
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
},
|
||||
|
||||
related: { //related colletions (and maybe items?)
|
||||
|
||||
options: [{
|
||||
label: 'Read',
|
||||
value: 'read',
|
||||
ngShow: "category == 'Inventory'"
|
||||
}, {
|
||||
label: 'Write',
|
||||
value: 'write',
|
||||
ngShow: "category == 'Inventory'"
|
||||
}, {
|
||||
label: 'Admin',
|
||||
value: 'admin',
|
||||
ngShow: "category == 'Inventory'"
|
||||
}, {
|
||||
label: 'Run',
|
||||
value: 'run',
|
||||
ngShow: "category == 'Deploy'"
|
||||
}, {
|
||||
label: 'Check',
|
||||
value: 'check',
|
||||
ngShow: "category == 'Deploy'"
|
||||
}],
|
||||
helpCollapse: [{
|
||||
hdr: 'Permission',
|
||||
ngBind: 'permissionTypeHelp'
|
||||
}]
|
||||
}
|
||||
},
|
||||
|
||||
buttons: {
|
||||
save: {
|
||||
ngClick: 'formSave()',
|
||||
ngDisabled: true
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true
|
||||
}
|
||||
},
|
||||
|
||||
related: { }
|
||||
|
||||
}); // Form
|
||||
@ -7,17 +7,16 @@
|
||||
*
|
||||
*/
|
||||
angular.module('ProjectStatusDefinition', [])
|
||||
.value(
|
||||
'ProjectStatusForm', {
|
||||
.value('ProjectStatusForm', {
|
||||
|
||||
name: 'project_update',
|
||||
editTitle: 'SCM Status',
|
||||
editTitle: 'SCM Status',
|
||||
well: false,
|
||||
'class': 'horizontal-narrow',
|
||||
|
||||
fields: {
|
||||
created: {
|
||||
label: 'Created',
|
||||
label: 'Created',
|
||||
type: 'text',
|
||||
readonly: true
|
||||
},
|
||||
@ -27,7 +26,7 @@ angular.module('ProjectStatusDefinition', [])
|
||||
readonly: true
|
||||
},
|
||||
result_stdout: {
|
||||
label: 'Std Out',
|
||||
label: 'Std Out',
|
||||
type: 'textarea',
|
||||
ngShow: "result_stdout",
|
||||
'class': 'mono-space',
|
||||
@ -35,7 +34,7 @@ angular.module('ProjectStatusDefinition', [])
|
||||
rows: 15
|
||||
},
|
||||
result_traceback: {
|
||||
label: 'Traceback',
|
||||
label: 'Traceback',
|
||||
type: 'textarea',
|
||||
ngShow: "result_traceback",
|
||||
'class': 'mono-space',
|
||||
|
||||
@ -5,16 +5,15 @@
|
||||
*
|
||||
* Form definition for Projects model
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
angular.module('ProjectFormDefinition', [])
|
||||
.value(
|
||||
'ProjectsForm', {
|
||||
|
||||
addTitle: 'Create Project', // Title in add mode
|
||||
editTitle: '{{ name }}', // Title in edit mode
|
||||
name: 'project', // entity or model name in singular form
|
||||
well: true, // Wrap the form with TB well
|
||||
.value('ProjectsForm', {
|
||||
|
||||
addTitle: 'Create Project', // Title in add mode
|
||||
editTitle: '{{ name }}', // Title in edit mode
|
||||
name: 'project', // entity or model name in singular form
|
||||
well: true, // Wrap the form with TB well
|
||||
forceListeners: true,
|
||||
|
||||
actions: {
|
||||
@ -26,8 +25,8 @@ angular.module('ProjectFormDefinition', [])
|
||||
icon: "icon-comments-alt",
|
||||
mode: 'edit',
|
||||
iconSize: 'large'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
@ -36,13 +35,13 @@ angular.module('ProjectFormDefinition', [])
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
capitalize: false
|
||||
},
|
||||
description: {
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
editRequired: false
|
||||
},
|
||||
},
|
||||
organization: {
|
||||
label: 'Organization',
|
||||
type: 'lookup',
|
||||
@ -52,35 +51,38 @@ angular.module('ProjectFormDefinition', [])
|
||||
editRequired: false,
|
||||
excludeMode: 'edit',
|
||||
ngClick: 'lookUpOrganization()',
|
||||
awRequiredWhen: {variable: "organizationrequired", init: "true" },
|
||||
awRequiredWhen: {
|
||||
variable: "organizationrequired",
|
||||
init: "true"
|
||||
},
|
||||
awPopOver: '<p>A project must have at least one organization. Pick one organization now to create the project, and then after ' +
|
||||
'the project is created you can add additional organizations.</p><p>Only super users and organization administrators are allowed ' +
|
||||
'to make changes to projects. Associating one or more organizations to a project determins which organizations admins have ' +
|
||||
'access to modify the project.',
|
||||
'the project is created you can add additional organizations.</p><p>Only super users and organization administrators are allowed ' +
|
||||
'to make changes to projects. Associating one or more organizations to a project determins which organizations admins have ' +
|
||||
'access to modify the project.',
|
||||
dataTitle: 'Organization',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right'
|
||||
},
|
||||
},
|
||||
scm_type: {
|
||||
label: 'SCM Type',
|
||||
type: 'select',
|
||||
ngOptions: 'type.label for type in scm_type_options',
|
||||
ngChange: 'scmChange()',
|
||||
addRequired: true,
|
||||
addRequired: true,
|
||||
editRequired: true
|
||||
},
|
||||
},
|
||||
missing_path_alert: {
|
||||
type: 'alertblock',
|
||||
"class": 'alert-info',
|
||||
type: 'alertblock',
|
||||
"class": 'alert-info',
|
||||
ngShow: "showMissingPlaybooksAlert && scm_type.value == ''",
|
||||
alertTxt: '<p class=\"text-justify\"><strong>WARNING:</strong> There are no unassigned playbook directories in the base ' +
|
||||
'project path {{ base_dir }}. Either the projects directory is empty, or all of the contents are already assigned to ' +
|
||||
'other projects. New projects can be checked out from source control by ' +
|
||||
'other projects. New projects can be checked out from source control by ' +
|
||||
'changing the SCM type option rather than specifying checkout paths manually. To continue with manual setup, log into ' +
|
||||
'the Tower host and ensure content is present in a subdirectory under {{ base_dir }}. Run "chown -R awx" on the content ' +
|
||||
'directory to ensure Tower can read the playbooks.</p>',
|
||||
closeable: false
|
||||
},
|
||||
},
|
||||
base_dir: {
|
||||
label: 'Project Base Path',
|
||||
type: 'textarea',
|
||||
@ -88,61 +90,69 @@ angular.module('ProjectFormDefinition', [])
|
||||
showonly: true,
|
||||
ngShow: "scm_type.value == ''",
|
||||
awPopOver: '<p>Base path used for locating playbooks. Directories found inside this path will be listed in the playbook directory drop-down. ' +
|
||||
'Together the base path and selected playbook directory provide the full path used to locate playbooks.</p>' +
|
||||
'<p>Use PROJECTS_ROOT in your environment settings file to determine the base path value.</p>',
|
||||
'Together the base path and selected playbook directory provide the full path used to locate playbooks.</p>' +
|
||||
'<p>Use PROJECTS_ROOT in your environment settings file to determine the base path value.</p>',
|
||||
dataTitle: 'Project Base Path',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right'
|
||||
},
|
||||
},
|
||||
local_path: {
|
||||
label: 'Playbook Directory',
|
||||
type: 'select',
|
||||
id: 'local-path-select',
|
||||
ngOptions: 'path.label for path in project_local_paths',
|
||||
awRequiredWhen: { variable: "pathRequired", init: false },
|
||||
awRequiredWhen: {
|
||||
variable: "pathRequired",
|
||||
init: false
|
||||
},
|
||||
ngShow: "scm_type.value == '' && !showMissingPlaybooksAlert",
|
||||
awPopOver: '<p>Select from the list of directories found in the base path.' +
|
||||
'Together the base path and the playbook directory provide the full path used to locate playbooks.</p>' +
|
||||
'<p>Use PROJECTS_ROOT in your environment settings file to determine the base path value.</p>',
|
||||
'Together the base path and the playbook directory provide the full path used to locate playbooks.</p>' +
|
||||
'<p>Use PROJECTS_ROOT in your environment settings file to determine the base path value.</p>',
|
||||
dataTitle: 'Project Path',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right'
|
||||
},
|
||||
},
|
||||
scm_url: {
|
||||
label: 'SCM URL',
|
||||
type: 'text',
|
||||
ngShow: "scm_type && scm_type.value !== ''",
|
||||
awRequiredWhen: { variable: "scmRequired", init: false },
|
||||
helpCollapse: [
|
||||
{ hdr: 'GIT URLs',
|
||||
content: '<p>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><strong>Note:</strong> If using SSH protocol for GitHub or Bitbucket, enter in the SSH key only, ' +
|
||||
'do not enter a username (other than git). Additionally, GitHub and Bitbucket do not support password authentication when using ' +
|
||||
'SSH protocol. GIT read only protocol (git://) does not use username or password information.',
|
||||
show: "scm_type.value == 'git'" },
|
||||
{ hdr: 'SVN URLs',
|
||||
content: '<p>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>',
|
||||
show: "scm_type.value == 'svn'" },
|
||||
{ hdr: 'Mercurial URLs',
|
||||
content: '<p>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><strong>Note:</strong> Mercurial does not support password authentication for SSH. ' +
|
||||
'If applicable, add the username, password and key below. Do not put the username and key in the URL. ' +
|
||||
'If using Bitbucket and SSH, do not supply your Bitbucket username.',
|
||||
show: "scm_type.value == 'hg'" }
|
||||
]
|
||||
awRequiredWhen: {
|
||||
variable: "scmRequired",
|
||||
init: false
|
||||
},
|
||||
helpCollapse: [{
|
||||
hdr: 'GIT URLs',
|
||||
content: '<p>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><strong>Note:</strong> If using SSH protocol for GitHub or Bitbucket, enter in the SSH key only, ' +
|
||||
'do not enter a username (other than git). Additionally, GitHub and Bitbucket do not support password authentication when using ' +
|
||||
'SSH protocol. GIT read only protocol (git://) does not use username or password information.',
|
||||
show: "scm_type.value == 'git'"
|
||||
}, {
|
||||
hdr: 'SVN URLs',
|
||||
content: '<p>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>',
|
||||
show: "scm_type.value == 'svn'"
|
||||
}, {
|
||||
hdr: 'Mercurial URLs',
|
||||
content: '<p>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><strong>Note:</strong> Mercurial does not support password authentication for SSH. ' +
|
||||
'If applicable, add the username, password and key below. Do not put the username and key in the URL. ' +
|
||||
'If using Bitbucket and SSH, do not supply your Bitbucket username.',
|
||||
show: "scm_type.value == 'hg'"
|
||||
}]
|
||||
},
|
||||
scm_branch: {
|
||||
labelBind: "scmBranchLabel",
|
||||
type: 'text',
|
||||
ngShow: "scm_type && scm_type.value !== ''",
|
||||
addRequired: false,
|
||||
editRequired: false
|
||||
},
|
||||
},
|
||||
credential: {
|
||||
label: 'SCM Credential',
|
||||
type: 'lookup',
|
||||
@ -150,111 +160,105 @@ angular.module('ProjectFormDefinition', [])
|
||||
sourceModel: 'credential',
|
||||
sourceField: 'name',
|
||||
ngClick: 'lookUpCredential()',
|
||||
addRequired: false,
|
||||
addRequired: false,
|
||||
editRequired: false
|
||||
},
|
||||
},
|
||||
checkbox_group: {
|
||||
label: 'SCM Update Options',
|
||||
type: 'checkbox_group',
|
||||
ngShow: "scm_type && scm_type.value !== ''",
|
||||
fields: [
|
||||
{
|
||||
name: 'scm_clean',
|
||||
label: 'Clean',
|
||||
type: 'checkbox',
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awPopOver: '<p>Remove any local modifications prior to performing an update.</p>',
|
||||
dataTitle: 'SCM Clean',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
},
|
||||
{
|
||||
name: 'scm_delete_on_update',
|
||||
label: 'Delete on Update',
|
||||
type: 'checkbox',
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awPopOver: '<p>Delete the local repository in its entirety prior to performing an update.</p><p>Depending on the size of the ' +
|
||||
'repository this may significantly increase the amount of time required to complete an update.</p>',
|
||||
dataTitle: 'SCM Delete',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
},
|
||||
{
|
||||
name: 'scm_update_on_launch',
|
||||
label: 'Update on Launch',
|
||||
type: 'checkbox',
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awPopOver: '<p>Each time a job runs using this project, perform an update to the local repository prior to starting the job.</p>',
|
||||
dataTitle: 'SCM Update',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
fields: [{
|
||||
name: 'scm_clean',
|
||||
label: 'Clean',
|
||||
type: 'checkbox',
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awPopOver: '<p>Remove any local modifications prior to performing an update.</p>',
|
||||
dataTitle: 'SCM Clean',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
}, {
|
||||
name: 'scm_delete_on_update',
|
||||
label: 'Delete on Update',
|
||||
type: 'checkbox',
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awPopOver: '<p>Delete the local repository in its entirety prior to performing an update.</p><p>Depending on the size of the ' +
|
||||
'repository this may significantly increase the amount of time required to complete an update.</p>',
|
||||
dataTitle: 'SCM Delete',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
}, {
|
||||
name: 'scm_update_on_launch',
|
||||
label: 'Update on Launch',
|
||||
type: 'checkbox',
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
awPopOver: '<p>Each time a job runs using this project, perform an update to the local repository prior to starting the job.</p>',
|
||||
dataTitle: 'SCM Update',
|
||||
dataContainer: 'body',
|
||||
dataPlacement: 'right',
|
||||
labelClass: 'checkbox-options'
|
||||
}]
|
||||
}
|
||||
},
|
||||
|
||||
buttons: { //for now always generates <button> tags
|
||||
save: {
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
reset: {
|
||||
buttons: {
|
||||
save: {
|
||||
ngClick: 'formSave()',
|
||||
ngDisabled: true
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
},
|
||||
ngDisabled: true
|
||||
}
|
||||
},
|
||||
|
||||
related: { //related colletions (and maybe items?)
|
||||
related: {
|
||||
organizations: {
|
||||
type: 'collection',
|
||||
title: 'Organizations',
|
||||
iterator: 'organization',
|
||||
open: false,
|
||||
|
||||
actions: {
|
||||
actions: {
|
||||
add: {
|
||||
ngClick: "add('organizations')",
|
||||
icon: 'icon-plus',
|
||||
label: 'Add',
|
||||
awToolTip: 'Add an organization'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Description'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "edit('organizations', \{\{ organization.id \}\}, '\{\{ organization.name \}\}')",
|
||||
ngClick: "edit('organizations', organization.id, organization.name)",
|
||||
icon: 'icon-edit',
|
||||
awToolTip: 'Edit the organization',
|
||||
'class': 'btn btn-default'
|
||||
},
|
||||
},
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "delete('organizations', \{\{ organization.id \}\}, '\{\{ organization.name \}\}', 'organizations')",
|
||||
ngClick: "delete('organizations', organization.id, organization.name, 'organizations')",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-danger',
|
||||
awToolTip: 'Delete the organization'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}); // Form
|
||||
|
||||
|
||||
}); // Form
|
||||
@ -4,14 +4,13 @@
|
||||
* Teams.js
|
||||
* Form definition for Team model
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
angular.module('TeamFormDefinition', [])
|
||||
.value(
|
||||
'TeamForm', {
|
||||
|
||||
addTitle: 'Create Team', //Legend in add mode
|
||||
editTitle: '{{ name }}', //Legend in edit mode
|
||||
.value('TeamForm', {
|
||||
|
||||
addTitle: 'Create Team', //Legend in add mode
|
||||
editTitle: '{{ name }}', //Legend in edit mode
|
||||
name: 'team',
|
||||
well: true,
|
||||
collapse: true,
|
||||
@ -28,8 +27,8 @@ angular.module('TeamFormDefinition', [])
|
||||
icon: "icon-comments-alt",
|
||||
mode: 'edit',
|
||||
iconSize: 'large'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
@ -38,228 +37,230 @@ angular.module('TeamFormDefinition', [])
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
capitalize: false
|
||||
},
|
||||
description: {
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
type: 'text',
|
||||
addRequired: false,
|
||||
editRequired: false
|
||||
},
|
||||
},
|
||||
organization: {
|
||||
label: 'Organization',
|
||||
type: 'lookup',
|
||||
sourceModel: 'organization',
|
||||
sourceField: 'name',
|
||||
ngClick: 'lookUpOrganization()',
|
||||
awRequiredWhen: {variable: "teamrequired", init: "true" }
|
||||
awRequiredWhen: {
|
||||
variable: "teamrequired",
|
||||
init: "true"
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
buttons: { //for now always generates <button> tags
|
||||
save: {
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
reset: {
|
||||
buttons: {
|
||||
save: {
|
||||
ngClick: 'formSave()',
|
||||
ngDisabled: true
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
},
|
||||
ngDisabled: true
|
||||
}
|
||||
},
|
||||
|
||||
related: { //related colletions (and maybe items?)
|
||||
|
||||
credentials: {
|
||||
related: {
|
||||
|
||||
credentials: {
|
||||
type: 'collection',
|
||||
title: 'Credentials',
|
||||
iterator: 'credential',
|
||||
open: false,
|
||||
|
||||
actions: {
|
||||
actions: {
|
||||
add: {
|
||||
ngClick: "add('credentials')",
|
||||
icon: 'icon-plus',
|
||||
label: 'Add',
|
||||
add: 'Add a new credential'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Description'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "edit('credentials', \{\{ credential.id \}\}, '\{\{ credential.name \}\}')",
|
||||
ngClick: "edit('credentials', credential.id, credential.name)",
|
||||
icon: 'icon-edit',
|
||||
awToolTip: 'Modify the credential',
|
||||
'class': 'btn btn-default'
|
||||
},
|
||||
},
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "delete('credentials', \{\{ credential.id \}\}, '\{\{ credential.name \}\}', 'credentials')",
|
||||
ngClick: "delete('credentials', credential.id, credential.name, 'credentials')",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-danger',
|
||||
awToolTip: 'Remove the credential'
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
permissions: {
|
||||
type: 'collection',
|
||||
title: 'Permissions',
|
||||
iterator: 'permission',
|
||||
open: false,
|
||||
|
||||
actions: {
|
||||
|
||||
actions: {
|
||||
add: {
|
||||
ngClick: "add('permissions')",
|
||||
icon: 'icon-plus',
|
||||
label: 'Add',
|
||||
awToolTip: 'Add a permission for this user',
|
||||
ngShow: 'PermissionAddAllowed'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
key: true,
|
||||
label: 'Name',
|
||||
ngClick: "edit('permissions', \{\{ permission.id \}\}, '\{\{ permission.name \}\}')"
|
||||
},
|
||||
ngClick: "edit('permissions', permission.id, permission.name)"
|
||||
},
|
||||
inventory: {
|
||||
label: 'Inventory',
|
||||
sourceModel: 'inventory',
|
||||
sourceField: 'name',
|
||||
ngBind: 'permission.summary_fields.inventory.name'
|
||||
},
|
||||
},
|
||||
project: {
|
||||
label: 'Project',
|
||||
sourceModel: 'project',
|
||||
sourceField: 'name',
|
||||
ngBind: 'permission.summary_fields.project.name'
|
||||
},
|
||||
permission_type: {
|
||||
label: 'Permission'
|
||||
}
|
||||
},
|
||||
|
||||
permission_type: {
|
||||
label: 'Permission'
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "edit('permissions', \{\{ permission.id \}\}, '\{\{ permission.name \}\}')",
|
||||
ngClick: "edit('permissions', permission.id, permission.name)",
|
||||
icon: 'icon-edit',
|
||||
awToolTip: 'Edit the permission',
|
||||
'class': 'btn btn-default'
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "delete('permissions', \{\{ permission.id \}\}, '\{\{ permission.name \}\}', 'permissions')",
|
||||
ngClick: "delete('permissions', permission.id, permission.name, 'permissions')",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-danger',
|
||||
awToolTip: 'Delete the permission',
|
||||
ngShow: 'PermissionAddAllowed'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
},
|
||||
|
||||
projects: {
|
||||
projects: {
|
||||
type: 'collection',
|
||||
title: 'Projects',
|
||||
iterator: 'project',
|
||||
open: false,
|
||||
|
||||
actions: {
|
||||
actions: {
|
||||
add: {
|
||||
ngClick: "add('projects')",
|
||||
icon: 'icon-plus',
|
||||
label: 'Add'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Description'
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "edit('projects', \{\{ project.id \}\}, '\{\{ project.name \}\}')",
|
||||
icon: 'icon-edit',
|
||||
awToolTip: 'Modify the project',
|
||||
'class': 'btn btn-default'
|
||||
},
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "delete('projects', \{\{ project.id \}\}, '\{\{ project.name \}\}', 'projects')",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-danger',
|
||||
awToolTip: 'Remove the project'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
users: {
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "edit('projects', project.id, project.name)",
|
||||
icon: 'icon-edit',
|
||||
awToolTip: 'Modify the project',
|
||||
'class': 'btn btn-default'
|
||||
},
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "delete('projects', project.id, project.name, 'projects')",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-danger',
|
||||
awToolTip: 'Remove the project'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
users: {
|
||||
type: 'collection',
|
||||
title: 'Users',
|
||||
iterator: 'user',
|
||||
open: false,
|
||||
|
||||
actions: {
|
||||
actions: {
|
||||
add: {
|
||||
ngClick: "add('users')",
|
||||
icon: 'icon-plus',
|
||||
label: 'Add',
|
||||
awToolTip: 'Add a user'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
username: {
|
||||
key: true,
|
||||
label: 'Username'
|
||||
},
|
||||
},
|
||||
first_name: {
|
||||
label: 'First Name'
|
||||
},
|
||||
},
|
||||
last_name: {
|
||||
label: 'Last Name'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "edit('users', \{\{ user.id \}\}, '\{\{ user.username \}\}')",
|
||||
ngClick: "edit('users', user.id, user.username)",
|
||||
icon: 'icon-edit',
|
||||
awToolTip: 'Edit user',
|
||||
'class': 'btn btn-default'
|
||||
},
|
||||
},
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "delete('users', \{\{ user.id \}\}, '\{\{ user.username \}\}', 'users')",
|
||||
ngClick: "delete('users', user.id, user.username, 'users')",
|
||||
icon: 'icon-terash',
|
||||
"class": 'btn-danger',
|
||||
awToolTip: 'Remove user'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}); //InventoryForm
|
||||
|
||||
}
|
||||
|
||||
}); //InventoryForm
|
||||
@ -4,16 +4,15 @@
|
||||
* Users.js
|
||||
* Form definition for User model
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
angular.module('UserFormDefinition', [])
|
||||
.value(
|
||||
'UserForm', {
|
||||
|
||||
addTitle: 'Create User', //Legend in add mode
|
||||
editTitle: '{{ username }}', //Legend in edit mode
|
||||
name: 'user', //Form name attribute
|
||||
well: true, //Wrap the form with TB well
|
||||
.value('UserForm', {
|
||||
|
||||
addTitle: 'Create User',
|
||||
editTitle: '{{ username }}',
|
||||
name: 'user',
|
||||
well: true,
|
||||
forceListeners: true,
|
||||
|
||||
actions: {
|
||||
@ -25,31 +24,31 @@ angular.module('UserFormDefinition', [])
|
||||
icon: "icon-comments-alt",
|
||||
mode: 'edit',
|
||||
iconSize: 'large'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
first_name: {
|
||||
first_name: {
|
||||
label: 'First Name',
|
||||
type: 'text',
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
capitalize: true
|
||||
},
|
||||
last_name: {
|
||||
},
|
||||
last_name: {
|
||||
label: 'Last Name',
|
||||
type: 'text',
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
capitalize: true
|
||||
},
|
||||
},
|
||||
email: {
|
||||
label: 'Email',
|
||||
type: 'email',
|
||||
addRequired: true,
|
||||
editRequired: true,
|
||||
autocomplete: false
|
||||
},
|
||||
},
|
||||
organization: {
|
||||
label: 'Organization',
|
||||
type: 'lookup',
|
||||
@ -57,14 +56,20 @@ angular.module('UserFormDefinition', [])
|
||||
sourceField: 'name',
|
||||
ngClick: 'lookUpOrganization()',
|
||||
excludeMode: 'edit',
|
||||
awRequiredWhen: { variable: "orgrequired", init: true }
|
||||
},
|
||||
awRequiredWhen: {
|
||||
variable: "orgrequired",
|
||||
init: true
|
||||
}
|
||||
},
|
||||
username: {
|
||||
label: 'Username',
|
||||
type: 'text',
|
||||
awRequiredWhen: { variable: "not_ldap_user", init: true },
|
||||
autocomplete: false
|
||||
awRequiredWhen: {
|
||||
variable: "not_ldap_user",
|
||||
init: true
|
||||
},
|
||||
autocomplete: false
|
||||
},
|
||||
password: {
|
||||
label: 'Password',
|
||||
type: 'password',
|
||||
@ -74,7 +79,7 @@ angular.module('UserFormDefinition', [])
|
||||
ngChange: "clearPWConfirm('password_confirm')",
|
||||
autocomplete: false,
|
||||
chkPass: true
|
||||
},
|
||||
},
|
||||
password_confirm: {
|
||||
label: 'Confirm Password',
|
||||
type: 'password',
|
||||
@ -84,7 +89,7 @@ angular.module('UserFormDefinition', [])
|
||||
awPassMatch: true,
|
||||
associated: 'password',
|
||||
autocomplete: false
|
||||
},
|
||||
},
|
||||
is_superuser: {
|
||||
label: 'Superuser (User has full system administration privileges.)',
|
||||
type: 'checkbox',
|
||||
@ -92,171 +97,169 @@ angular.module('UserFormDefinition', [])
|
||||
falseValue: 'false',
|
||||
"default": 'false',
|
||||
ngShow: "current_user['is_superuser'] == true"
|
||||
},
|
||||
ldap_user: {
|
||||
label: 'Created by LDAP',
|
||||
},
|
||||
ldap_user: {
|
||||
label: 'Created by LDAP',
|
||||
type: 'checkbox',
|
||||
readonly: true
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
buttons: { //for now always generates <button> tags
|
||||
save: {
|
||||
ngClick: 'formSave()', //$scope.function to call on click, optional
|
||||
ngDisabled: true //Disable when $pristine or $invalid, optional
|
||||
},
|
||||
reset: {
|
||||
buttons: {
|
||||
save: {
|
||||
ngClick: 'formSave()',
|
||||
ngDisabled: true
|
||||
},
|
||||
reset: {
|
||||
ngClick: 'formReset()',
|
||||
ngDisabled: true //Disabled when $pristine
|
||||
}
|
||||
},
|
||||
ngDisabled: true
|
||||
}
|
||||
},
|
||||
|
||||
related: {
|
||||
|
||||
related: { //related colletions (and maybe items?)
|
||||
|
||||
credentials: {
|
||||
type: 'collection',
|
||||
title: 'Credentials',
|
||||
iterator: 'credential',
|
||||
open: false,
|
||||
|
||||
actions: {
|
||||
actions: {
|
||||
add: {
|
||||
ngClick: "add('credentials')",
|
||||
icon: 'icon-plus',
|
||||
label: 'Add',
|
||||
awToolTip: 'Add a credential for this user'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Description'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "edit('credentials', \{\{ credential.id \}\}, '\{\{ credential.name \}\}')",
|
||||
ngClick: "edit('credentials', credential.id, credential.name)",
|
||||
icon: 'icon-edit',
|
||||
awToolTip: 'Edit the credential',
|
||||
'class': 'btn btn-default'
|
||||
},
|
||||
},
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "delete('credentials', \{\{ credential.id \}\}, '\{\{ credential.name \}\}', 'credentials')",
|
||||
ngClick: "delete('credentials', credential.id, credential.name, 'credentials')",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-danger',
|
||||
awToolTip: 'Delete the credential'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
permissions: {
|
||||
type: 'collection',
|
||||
title: 'Permissions',
|
||||
iterator: 'permission',
|
||||
open: false,
|
||||
|
||||
actions: {
|
||||
|
||||
actions: {
|
||||
add: {
|
||||
ngClick: "add('permissions')",
|
||||
icon: 'icon-plus',
|
||||
label: 'Add',
|
||||
awToolTip: 'Add a permission for this user',
|
||||
ngShow: 'PermissionAddAllowed'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
key: true,
|
||||
label: 'Name',
|
||||
ngClick: "edit('permissions', \{\{ permission.id \}\}, '\{\{ permission.name \}\}')"
|
||||
},
|
||||
ngClick: "edit('permissions', permission.id, permission.name)"
|
||||
},
|
||||
inventory: {
|
||||
label: 'Inventory',
|
||||
sourceModel: 'inventory',
|
||||
sourceField: 'name',
|
||||
ngBind: 'permission.summary_fields.inventory.name'
|
||||
},
|
||||
},
|
||||
project: {
|
||||
label: 'Project',
|
||||
sourceModel: 'project',
|
||||
sourceField: 'name',
|
||||
ngBind: 'permission.summary_fields.project.name'
|
||||
},
|
||||
},
|
||||
permission_type: {
|
||||
label: 'Permission'
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "edit('permissions', \{\{ permission.id \}\}, '\{\{ permission.name \}\}')",
|
||||
ngClick: "edit('permissions', permission.id, permission.name)",
|
||||
icon: 'icon-edit',
|
||||
awToolTip: 'Edit the permission',
|
||||
'class': 'btn btn-default'
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "delete('permissions', \{\{ permission.id \}\}, '\{\{ permission.name \}\}', 'permissions')",
|
||||
ngClick: "delete('permissions', permission.id, permission.name, 'permissions')",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-danger',
|
||||
awToolTip: 'Delete the permission',
|
||||
ngShow: 'PermissionAddAllowed'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
admin_of_organizations: { // Assumes a plural name (e.g. things)
|
||||
},
|
||||
|
||||
admin_of_organizations: { // Assumes a plural name (e.g. things)
|
||||
type: 'collection',
|
||||
title: 'Admin of Organizations',
|
||||
iterator: 'adminof', // Singular form of name (e.g. thing)
|
||||
open: false, // Open accordion on load?
|
||||
iterator: 'adminof', // Singular form of name (e.g. thing)
|
||||
open: false, // Open accordion on load?
|
||||
base: '/organizations',
|
||||
|
||||
actions: {
|
||||
},
|
||||
|
||||
actions: {},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Description'
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
organizations: {
|
||||
organizations: {
|
||||
type: 'collection',
|
||||
title: 'Organizations',
|
||||
iterator: 'organization',
|
||||
open: false,
|
||||
|
||||
actions: {
|
||||
},
|
||||
|
||||
actions: {},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Description'
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
teams: {
|
||||
type: 'collection',
|
||||
@ -264,19 +267,18 @@ angular.module('UserFormDefinition', [])
|
||||
iterator: 'team',
|
||||
open: false,
|
||||
|
||||
actions: {
|
||||
},
|
||||
actions: {},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Description'
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
projects: {
|
||||
type: 'collection',
|
||||
@ -284,21 +286,19 @@ angular.module('UserFormDefinition', [])
|
||||
iterator: 'project',
|
||||
open: false,
|
||||
|
||||
actions: {
|
||||
},
|
||||
actions: {},
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Description'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}); //UserForm
|
||||
}
|
||||
|
||||
}); //UserForm
|
||||
@ -1,65 +1,86 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* InventoryGroups.js
|
||||
* InventoryGroups.js
|
||||
*
|
||||
* Help object for inventory groups/hosts page.
|
||||
*
|
||||
* @dict
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('InventoryGroupsHelpDefinition', [])
|
||||
.value(
|
||||
'InventoryGroupsHelp', {
|
||||
.value('InventoryGroupsHelp', {
|
||||
story: {
|
||||
hdr: 'Building your inventory',
|
||||
width: 510,
|
||||
height: 560,
|
||||
steps: [
|
||||
{
|
||||
steps: [{
|
||||
intro: 'Start by creating a group:',
|
||||
img: { src: 'groups001.png', maxWidth: 338 , maxHeight: 222 },
|
||||
img: {
|
||||
src: 'groups001.png',
|
||||
maxWidth: 338,
|
||||
maxHeight: 222
|
||||
},
|
||||
box: "Click <i class=\"fa fa-plus\"></i> on the groups list (the left side of the page) to add a new group.",
|
||||
autoOffNotice: true
|
||||
},
|
||||
{
|
||||
}, {
|
||||
intro: 'Enter group properties:',
|
||||
img: { src: 'groups002.png', maxWidth: 443, maxHeight: 251 },
|
||||
img: {
|
||||
src: 'groups002.png',
|
||||
maxWidth: 443,
|
||||
maxHeight: 251
|
||||
},
|
||||
box: 'Enter the group name, a description and any inventory variables. Variables can be entered using either JSON or YAML syntax. ' +
|
||||
'For more on inventory variables, see <a href=\"http://docs.ansible.com/intro_inventory.html\" target="_blank"> ' +
|
||||
'docs.ansible.com/intro_inventory.html</a>'
|
||||
},
|
||||
{
|
||||
'For more on inventory variables, see <a href=\"http://docs.ansible.com/intro_inventory.html\" target="_blank"> ' +
|
||||
'docs.ansible.com/intro_inventory.html</a>'
|
||||
}, {
|
||||
intro: 'Cloud inventory: select cloud source',
|
||||
img: { src: 'groups003.png', maxWidth: 412, maxHeight: 215 },
|
||||
img: {
|
||||
src: 'groups003.png',
|
||||
maxWidth: 412,
|
||||
maxHeight: 215
|
||||
},
|
||||
box: "For a cloud inventory, choose the cloud provider from the list and select your credentials. If you have not already setup " +
|
||||
"credentials for the provider, you will need to do that first on the <a href=\"/#/credentials\" " +
|
||||
"target=\"_blank\">Credentials</a> tab."
|
||||
},
|
||||
{
|
||||
"credentials for the provider, you will need to do that first on the <a href=\"/#/credentials\" " +
|
||||
"target=\"_blank\">Credentials</a> tab."
|
||||
}, {
|
||||
intro: 'Cloud inventory: synchronize Tower with the cloud',
|
||||
img: { src: 'groups004.png', maxWidth: 261, maxHeight: 221 },
|
||||
img: {
|
||||
src: 'groups004.png',
|
||||
maxWidth: 261,
|
||||
maxHeight: 221
|
||||
},
|
||||
box: "To pull the cloud inventory into Tower, initiate an inventory sync by clicking <i class=\"fa fa-exchange\"></i>."
|
||||
},
|
||||
{
|
||||
}, {
|
||||
intro: "Groups can have subgroups:",
|
||||
img: { src: 'groups005.png', maxWidth: 430, maxHeight: 206 },
|
||||
img: {
|
||||
src: 'groups005.png',
|
||||
maxWidth: 430,
|
||||
maxHeight: 206
|
||||
},
|
||||
box: "<div class=\"text-left\">First, select a group. Then click <i class=\"fa fa-plus\"></i> to create a new group. The new group " +
|
||||
"will be added to the selected group.</div>"
|
||||
},
|
||||
{
|
||||
"will be added to the selected group.</div>"
|
||||
}, {
|
||||
intro: 'Copy or move groups:',
|
||||
img: { src: 'groups006.png', maxWidth: 263, maxHeight: 211 },
|
||||
box: "<div class=\"text-left\">Copy or move a group by dragging and dropping its name onto another group name. A dialog will appear " +
|
||||
"asking if the group should be coppied or moved.</div>"
|
||||
img: {
|
||||
src: 'groups006.png',
|
||||
maxWidth: 263,
|
||||
maxHeight: 211
|
||||
},
|
||||
{
|
||||
box: "<div class=\"text-left\">Copy or move a group by dragging and dropping its name onto another group name. A dialog will appear " +
|
||||
"asking if the group should be coppied or moved.</div>"
|
||||
}, {
|
||||
intro: 'Adding hosts:',
|
||||
img: { src: 'groups007.png', maxWidth: 466, maxHeight: 178 },
|
||||
box: "<div class=\"text-left\"><p>First, select a Group. " +
|
||||
"Then click <i class=\"fa fa-plus\"></i> on the hosts list (the right side of the page) to create a host. " +
|
||||
"The new host will be part of the selected group.</p><p>Note hosts cannot be added to the All Hosts group.</p></div>"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
img: {
|
||||
src: 'groups007.png',
|
||||
maxWidth: 466,
|
||||
maxHeight: 178
|
||||
},
|
||||
box: "<div class=\"text-left\"><p>First, select a Group. " +
|
||||
"Then click <i class=\"fa fa-plus\"></i> on the hosts list (the right side of the page) to create a host. " +
|
||||
"The new host will be part of the selected group.</p><p>Note hosts cannot be added to the All Hosts group.</p></div>"
|
||||
}]
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* InventoryHosts.js
|
||||
* Help object for Inventory-> Hosts page.
|
||||
*
|
||||
*
|
||||
*/
|
||||
angular.module('InventoryHostsHelpDefinition', [])
|
||||
.value(
|
||||
'InventoryHostsHelp', {
|
||||
story: {
|
||||
hdr: 'Managing Hosts',
|
||||
steps: {
|
||||
step1: {
|
||||
intro: 'Start by selecting a group:',
|
||||
img: { src: 'help003.png', maxWidth: 315 , maxHeight: 198 },
|
||||
box: "On the group selector, click the name of a group. Hosts contained in the group" +
|
||||
" will appear on the right.",
|
||||
height: 500
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -4,102 +4,103 @@
|
||||
* helpers/Access.js
|
||||
*
|
||||
* Routines for checking user access and license state
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('AccessHelper', ['RestServices', 'Utilities', 'ngCookies'])
|
||||
.factory('CheckAccess', ['$rootScope', 'Alert', 'Rest', 'GetBasePath','ProcessErrors',
|
||||
function($rootScope, Alert, Rest, GetBasePath, ProcessErrors) {
|
||||
return function(params) {
|
||||
// set PermissionAddAllowed to true or false based on user access. admins and org admins are granted
|
||||
// accesss.
|
||||
var me = $rootScope.current_user;
|
||||
var scope = params.scope;
|
||||
'use strict';
|
||||
|
||||
if (me.is_superuser) {
|
||||
scope.PermissionAddAllowed = true;
|
||||
}
|
||||
else {
|
||||
if (me.related.admin_of_organizations) {
|
||||
Rest.setUrl(me.related.admin_of_organizations);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
if (data.results.length > 0) {
|
||||
scope.PermissionAddAllowed = true;
|
||||
}
|
||||
else {
|
||||
scope.PermissionAddAllowed = false;
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Call to ' + me.related.admin_of_organizations +
|
||||
' failed. DELETE returned status: ' + status });
|
||||
});
|
||||
}
|
||||
}
|
||||
//if (!access) {
|
||||
// Alert('Access Denied', 'You do not have access to this function. Please contact your system administrator.');
|
||||
//}
|
||||
//return access;
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('CheckLicense', ['$rootScope', '$cookieStore', 'Alert', '$location', 'Authorization',
|
||||
function($rootScope, $cookieStore, Alert, $location, Authorization) {
|
||||
return function() {
|
||||
// Check license status and alert the user, if needed
|
||||
var status = 'success';
|
||||
var hdr, msg;
|
||||
var license = $cookieStore.get('license');
|
||||
|
||||
var purchase_msg = '<p>To purchase a license or extend an existing license ' +
|
||||
'<a href="http://www.ansible.com/ansible-pricing" target="_blank"><strong>visit the Ansible online store</strong></a>, ' +
|
||||
'or visit <strong><a href="https://support.ansible.com" target="_blank">support.ansible.com</a></strong> for assistance.</p>';
|
||||
angular.module('AccessHelper', ['RestServices', 'Utilities', 'ngCookies'])
|
||||
.factory('CheckAccess', ['$rootScope', 'Alert', 'Rest', 'GetBasePath', 'ProcessErrors',
|
||||
function ($rootScope, Alert, Rest, GetBasePath, ProcessErrors) {
|
||||
return function (params) {
|
||||
// set PermissionAddAllowed to true or false based on user access. admins and org admins are granted
|
||||
// accesss.
|
||||
var me = $rootScope.current_user,
|
||||
scope = params.scope;
|
||||
|
||||
if (license && !Authorization.licenseTested()) {
|
||||
// This is our first time evaluating the license
|
||||
license['tested'] = true;
|
||||
$cookieStore.remove('license');
|
||||
$cookieStore.put('license', license);
|
||||
$rootScope.license_tested = true;
|
||||
if (license['valid_key'] !== undefined && license['valid_key'] == false) {
|
||||
// The license is invalid. Stop the user from logging in.
|
||||
status = 'alert-danger';
|
||||
hdr = 'License Error';
|
||||
msg = '<p>There is a problem with the /etc/awx/license file on your Tower server. Check to make sure Tower can access ' +
|
||||
'the file.</p>' + purchase_msg;
|
||||
Alert(hdr, msg, status, null, false, true);
|
||||
}
|
||||
else if (license['demo'] !== undefined && license['demo'] == true) {
|
||||
// demo
|
||||
status = 'alert-info';
|
||||
hdr = 'Tower Demo';
|
||||
msg = '<p>Thank you for trying Ansible Tower. You can use this edition to manage up to 10 hosts free.</p>' +
|
||||
purchase_msg;
|
||||
Alert(hdr, msg, status);
|
||||
}
|
||||
if (license['date_expired'] !== undefined && license['date_expired'] == true) {
|
||||
// expired
|
||||
status = 'alert-info';
|
||||
hdr = 'License Expired';
|
||||
msg = '<p>Your Ansible Tower License has expired and is no longer compliant. You can continue, but you will be ' +
|
||||
'unable to add any additional hosts.</p>' + purchase_msg;
|
||||
Alert(hdr, msg, status);
|
||||
}
|
||||
else if (license['date_warning'] !== undefined && license['date_warning'] == true) {
|
||||
status = 'alert-info';
|
||||
hdr = 'License Warning';
|
||||
msg = '<p>Your Ansible Tower license is about to expire!</p>' + purchase_msg;
|
||||
Alert(hdr, msg, status);
|
||||
}
|
||||
if (license['free_instances'] !== undefined && parseInt(license['free_instances']) <= 0) {
|
||||
status = 'alert-info';
|
||||
hdr = 'License Warning';
|
||||
msg = '<p>Your Ansible Tower license has reached capacity for the number of managed ' +
|
||||
'hosts allowed. You will not be able to add any additional hosts.</p>' + purchase_msg;
|
||||
Alert(hdr, msg, status, null, true);
|
||||
}
|
||||
if (me.is_superuser) {
|
||||
scope.PermissionAddAllowed = true;
|
||||
} else {
|
||||
if (me.related.admin_of_organizations) {
|
||||
Rest.setUrl(me.related.admin_of_organizations);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
if (data.results.length > 0) {
|
||||
scope.PermissionAddAllowed = true;
|
||||
} else {
|
||||
scope.PermissionAddAllowed = false;
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Call to ' + me.related.admin_of_organizations +
|
||||
' failed. DELETE returned status: ' + status
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
//if (!access) {
|
||||
// Alert('Access Denied', 'You do not have access to this function. Please contact your system administrator.');
|
||||
//}
|
||||
//return access;
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
.factory('CheckLicense', ['$rootScope', '$cookieStore', 'Alert', '$location', 'Authorization',
|
||||
function ($rootScope, $cookieStore, Alert, $location, Authorization) {
|
||||
return function () {
|
||||
// Check license status and alert the user, if needed
|
||||
var status = 'success',
|
||||
hdr, msg,
|
||||
license = $cookieStore.get('license'),
|
||||
purchase_msg = '<p>To purchase a license or extend an existing license ' +
|
||||
'<a href="http://www.ansible.com/ansible-pricing" target="_blank"><strong>visit the Ansible online store</strong></a>, ' +
|
||||
'or visit <strong><a href="https://support.ansible.com" target="_blank">support.ansible.com</a></strong> for assistance.</p>';
|
||||
|
||||
if (license && !Authorization.licenseTested()) {
|
||||
// This is our first time evaluating the license
|
||||
license.tested = true;
|
||||
$cookieStore.remove('license');
|
||||
$cookieStore.put('license', license);
|
||||
$rootScope.license_tested = true;
|
||||
if (license.valid_key !== undefined && license.valid_key === false) {
|
||||
// The license is invalid. Stop the user from logging in.
|
||||
status = 'alert-danger';
|
||||
hdr = 'License Error';
|
||||
msg = '<p>There is a problem with the /etc/awx/license file on your Tower server. Check to make sure Tower can access ' +
|
||||
'the file.</p>' + purchase_msg;
|
||||
Alert(hdr, msg, status, null, false, true);
|
||||
} else if (license.demo !== undefined && license.demo === true) {
|
||||
// demo
|
||||
status = 'alert-info';
|
||||
hdr = 'Tower Demo';
|
||||
msg = '<p>Thank you for trying Ansible Tower. You can use this edition to manage up to 10 hosts free.</p>' +
|
||||
purchase_msg;
|
||||
Alert(hdr, msg, status);
|
||||
}
|
||||
if (license.date_expired !== undefined && license.date_expired === true) {
|
||||
// expired
|
||||
status = 'alert-info';
|
||||
hdr = 'License Expired';
|
||||
msg = '<p>Your Ansible Tower License has expired and is no longer compliant. You can continue, but you will be ' +
|
||||
'unable to add any additional hosts.</p>' + purchase_msg;
|
||||
Alert(hdr, msg, status);
|
||||
} else if (license.date_warning !== undefined && license.date_warning === true) {
|
||||
status = 'alert-info';
|
||||
hdr = 'License Warning';
|
||||
msg = '<p>Your Ansible Tower license is about to expire!</p>' + purchase_msg;
|
||||
Alert(hdr, msg, status);
|
||||
}
|
||||
if (license.free_instances !== undefined && parseInt(license.free_instances) <= 0) {
|
||||
status = 'alert-info';
|
||||
hdr = 'License Warning';
|
||||
msg = '<p>Your Ansible Tower license has reached capacity for the number of managed ' +
|
||||
'hosts allowed. You will not be able to add any additional hosts.</p>' + purchase_msg;
|
||||
Alert(hdr, msg, status, null, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}]);
|
||||
]);
|
||||
@ -3,78 +3,62 @@
|
||||
*
|
||||
* ChildrenHelper
|
||||
*
|
||||
* Used in job_events to expand/collapse children by setting the
|
||||
* Used in job_events to expand/collapse children by setting the
|
||||
* 'show' attribute of each job_event in the set of job_events.
|
||||
* See the filter in job_events.js list.
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('ChildrenHelper', ['RestServices', 'Utilities'])
|
||||
.factory('ToggleChildren', ['Alert', 'Rest', 'GetBasePath','ProcessErrors','FormatDate',
|
||||
function(Alert, Rest, GetBasePath, ProcessErrors, FormatDate) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var list = params.list;
|
||||
var id = params.id;
|
||||
var set = scope[list.name]; // set is now a pointer to scope[list.name]
|
||||
|
||||
function expand(node) {
|
||||
set[node]['ngicon'] = 'fa fa-minus-square-o node-toggle';
|
||||
for (var i = node + 1; i < set.length; i++) {
|
||||
if (set[i].parent == set[node].id) {
|
||||
set[i]['show'] = true;
|
||||
//if (set[i].related.children) {
|
||||
// expand(i);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function collapse(node) {
|
||||
set[node]['ngicon'] = 'fa fa-plus-square-o node-toggle';
|
||||
for (var i = node + 1; i < set.length; i++) {
|
||||
if (set[i].parent == set[node].id) {
|
||||
set[i]['show'] = false;
|
||||
if (set[i]['related']['children']) {
|
||||
collapse(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'use strict';
|
||||
|
||||
// Scan the array list and find the clicked element
|
||||
var clicked;
|
||||
var found = false;
|
||||
for (var i = 0; i < set.length && found == false; i++){
|
||||
if (set[i].id == id) {
|
||||
clicked = i;
|
||||
found = true;
|
||||
angular.module('ChildrenHelper', ['RestServices', 'Utilities'])
|
||||
.factory('ToggleChildren', [ function () {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
list = params.list,
|
||||
id = params.id,
|
||||
set = scope[list.name],
|
||||
i, clicked, found = false;
|
||||
|
||||
function expand(node) {
|
||||
var i;
|
||||
set[node].ngicon = 'fa fa-minus-square-o node-toggle';
|
||||
for (i = node + 1; i < set.length; i++) {
|
||||
if (set[i].parent === set[node].id) {
|
||||
set[i].show = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Expand or collapse children based on clicked element's icon
|
||||
if (/plus-square-o/.test(set[clicked]['ngicon'])) {
|
||||
// Expand: lookup and display children
|
||||
expand(clicked);
|
||||
}
|
||||
else if (/minus-square-o/.test(set[clicked]['ngicon'])) {
|
||||
collapse(clicked);
|
||||
}
|
||||
|
||||
function collapse(node) {
|
||||
var i;
|
||||
set[node].ngicon = 'fa fa-plus-square-o node-toggle';
|
||||
for (i = node + 1; i < set.length; i++) {
|
||||
if (set[i].parent === set[node].id) {
|
||||
set[i].show = false;
|
||||
if (set[i].related.children) {
|
||||
collapse(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scan the array list and find the clicked element
|
||||
for (i = 0; i < set.length && found === false; i++) {
|
||||
if (set[i].id === id) {
|
||||
clicked = i;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Expand or collapse children based on clicked element's icon
|
||||
if (/plus-square-o/.test(set[clicked].ngicon)) {
|
||||
// Expand: lookup and display children
|
||||
expand(clicked);
|
||||
} else if (/minus-square-o/.test(set[clicked].ngicon)) {
|
||||
collapse(clicked);
|
||||
}
|
||||
};
|
||||
}
|
||||
}]);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
]);
|
||||
@ -7,176 +7,185 @@
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('CredentialsHelper', ['Utilities'])
|
||||
|
||||
.factory('KindChange', [ 'Empty', function(Empty) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var form = params.form;
|
||||
var reset = params.reset;
|
||||
'use strict';
|
||||
|
||||
// Put things in a default state
|
||||
scope['usernameLabel'] = 'Username';
|
||||
scope['aws_required'] = false;
|
||||
scope['rackspace_required'] = false;
|
||||
scope['sshKeyDataLabel'] = 'SSH Private Key';
|
||||
|
||||
if (!Empty(scope['kind'])) {
|
||||
// Apply kind specific settings
|
||||
switch(scope['kind'].value) {
|
||||
angular.module('CredentialsHelper', ['Utilities'])
|
||||
|
||||
.factory('KindChange', ['Empty',
|
||||
function (Empty) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
reset = params.reset,
|
||||
collapse, id;
|
||||
|
||||
// Put things in a default state
|
||||
scope.usernameLabel = 'Username';
|
||||
scope.aws_required = false;
|
||||
scope.rackspace_required = false;
|
||||
scope.sshKeyDataLabel = 'SSH Private Key';
|
||||
|
||||
if (!Empty(scope.kind)) {
|
||||
// Apply kind specific settings
|
||||
switch (scope.kind.value) {
|
||||
case 'aws':
|
||||
scope['aws_required'] = true;
|
||||
break;
|
||||
case 'rax':
|
||||
scope['rackspace_required'] = true;
|
||||
scope.aws_required = true;
|
||||
break;
|
||||
case 'rax':
|
||||
scope.rackspace_required = true;
|
||||
break;
|
||||
case 'ssh':
|
||||
scope['usernameLabel'] = 'SSH Username';
|
||||
break;
|
||||
case 'scm':
|
||||
scope['sshKeyDataLabel'] = 'SCM Private Key';
|
||||
scope.usernameLabel = 'SSH Username';
|
||||
break;
|
||||
case 'scm':
|
||||
scope.sshKeyDataLabel = 'SCM Private Key';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset all the field values related to Kind.
|
||||
if (reset) {
|
||||
scope['access_key'] = null;
|
||||
scope['secret_key'] = null;
|
||||
scope['api_key'] = null;
|
||||
scope['username'] = null;
|
||||
scope['password'] = null;
|
||||
scope['password_confirm'] = null;
|
||||
scope['ssh_key_data'] = null;
|
||||
scope['ssh_key_unlock'] = null;
|
||||
scope['ssh_key_unlock_confirm'] = null;
|
||||
scope['sudo_username'] = null;
|
||||
scope['sudo_password'] = null;
|
||||
scope['sudo_password_confirm'] = null;
|
||||
}
|
||||
|
||||
// Collapse or open help widget based on whether scm value is selected
|
||||
var collapse = $('#credential_kind').parent().find('.panel-collapse').first();
|
||||
var id = collapse.attr('id');
|
||||
if (!Empty(scope.kind) && scope.kind.value !== '') {
|
||||
if ( $('#' + id + '-icon').hasClass('icon-minus') ) {
|
||||
scope.accordionToggle('#' + id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( $('#' + id + '-icon').hasClass('icon-plus') ) {
|
||||
scope.accordionToggle('#' + id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}])
|
||||
|
||||
|
||||
.factory('OwnerChange', [ function() {
|
||||
return function(params) {
|
||||
var scope = params.scope;
|
||||
var owner = scope['owner'];
|
||||
if (owner == 'team') {
|
||||
scope['team_required'] = true;
|
||||
scope['user_required'] = false;
|
||||
scope['user'] = null;
|
||||
scope['user_username'] = null;
|
||||
}
|
||||
else {
|
||||
scope['team_required'] = false;
|
||||
scope['user_required'] = true;
|
||||
scope['team'] = null;
|
||||
scope['team_name'] = null;
|
||||
}
|
||||
|
||||
}
|
||||
}])
|
||||
|
||||
|
||||
.factory('FormSave', ['$location', 'Rest', 'ProcessErrors', 'Empty', 'GetBasePath', 'CredentialForm', 'ReturnToCaller', 'Wait',
|
||||
function($location, Rest, ProcessErrors, Empty, GetBasePath, CredentialForm, ReturnToCaller, Wait) {
|
||||
return function(params) {
|
||||
var scope = params.scope;
|
||||
var mode = params.mode; // add or edit
|
||||
var form = CredentialForm;
|
||||
var data = {}
|
||||
|
||||
for (var fld in form.fields) {
|
||||
if (fld !== 'access_key' && fld !== 'secret_key' && fld !== 'ssh_username' &&
|
||||
fld !== 'ssh_password') {
|
||||
if (scope[fld] === null) {
|
||||
data[fld] = "";
|
||||
}
|
||||
else {
|
||||
data[fld] = scope[fld];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Empty(scope.team)) {
|
||||
data.team = scope.team;
|
||||
data.user = "";
|
||||
}
|
||||
else {
|
||||
data.user = scope.user;
|
||||
data.team = "";
|
||||
}
|
||||
|
||||
data['kind'] = scope['kind'].value;
|
||||
// Reset all the field values related to Kind.
|
||||
if (reset) {
|
||||
scope.access_key = null;
|
||||
scope.secret_key = null;
|
||||
scope.api_key = null;
|
||||
scope.username = null;
|
||||
scope.password = null;
|
||||
scope.password_confirm = null;
|
||||
scope.ssh_key_data = null;
|
||||
scope.ssh_key_unlock = null;
|
||||
scope.ssh_key_unlock_confirm = null;
|
||||
scope.sudo_username = null;
|
||||
scope.sudo_password = null;
|
||||
scope.sudo_password_confirm = null;
|
||||
}
|
||||
|
||||
switch (data['kind']) {
|
||||
case 'ssh':
|
||||
data['password'] = scope['ssh_password'];
|
||||
break;
|
||||
// Collapse or open help widget based on whether scm value is selected
|
||||
collapse = $('#credential_kind').parent().find('.panel-collapse').first();
|
||||
id = collapse.attr('id');
|
||||
if (!Empty(scope.kind) && scope.kind.value !== '') {
|
||||
if ($('#' + id + '-icon').hasClass('icon-minus')) {
|
||||
scope.accordionToggle('#' + id);
|
||||
}
|
||||
} else {
|
||||
if ($('#' + id + '-icon').hasClass('icon-plus')) {
|
||||
scope.accordionToggle('#' + id);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
.factory('OwnerChange', [
|
||||
function () {
|
||||
return function (params) {
|
||||
var scope = params.scope,
|
||||
owner = scope.owner;
|
||||
if (owner === 'team') {
|
||||
scope.team_required = true;
|
||||
scope.user_required = false;
|
||||
scope.user = null;
|
||||
scope.user_username = null;
|
||||
} else {
|
||||
scope.team_required = false;
|
||||
scope.user_required = true;
|
||||
scope.team = null;
|
||||
scope.team_name = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
.factory('FormSave', ['$location', 'Alert', 'Rest', 'ProcessErrors', 'Empty', 'GetBasePath', 'CredentialForm', 'ReturnToCaller', 'Wait',
|
||||
function ($location, Alert, Rest, ProcessErrors, Empty, GetBasePath, CredentialForm, ReturnToCaller, Wait) {
|
||||
return function (params) {
|
||||
var scope = params.scope,
|
||||
mode = params.mode,
|
||||
form = CredentialForm,
|
||||
data = {}, fld, url;
|
||||
|
||||
for (fld in form.fields) {
|
||||
if (fld !== 'access_key' && fld !== 'secret_key' && fld !== 'ssh_username' &&
|
||||
fld !== 'ssh_password') {
|
||||
if (scope[fld] === null) {
|
||||
data[fld] = "";
|
||||
} else {
|
||||
data[fld] = scope[fld];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Empty(scope.team)) {
|
||||
data.team = scope.team;
|
||||
data.user = "";
|
||||
} else {
|
||||
data.user = scope.user;
|
||||
data.team = "";
|
||||
}
|
||||
|
||||
data.kind = scope.kind.value;
|
||||
|
||||
switch (data.kind) {
|
||||
case 'ssh':
|
||||
data.password = scope.ssh_password;
|
||||
break;
|
||||
case 'aws':
|
||||
data['username'] = scope['access_key'];
|
||||
data['password'] = scope['secret_key'];
|
||||
data.username = scope.access_key;
|
||||
data.password = scope.secret_key;
|
||||
break;
|
||||
case 'rax':
|
||||
data['password'] = scope['api_key'];
|
||||
data.password = scope.api_key;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Empty(data.team) && Empty(data.user)) {
|
||||
Alert('Missing User or Team', 'You must provide either a User or a Team. If this credential will only be accessed by a specific ' +
|
||||
'user, select a User. To allow a team of users to access this credential, select a Team.', 'alert-danger');
|
||||
}
|
||||
else {
|
||||
Wait('start');
|
||||
if (mode == 'add') {
|
||||
var url = (!Empty(data.team)) ? GetBasePath('teams') + data.team + '/credentials/' :
|
||||
GetBasePath('users') + data.user + '/credentials/';
|
||||
Rest.setUrl(url);
|
||||
Rest.post(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
(base == 'credentials') ? ReturnToCaller() : ReturnToCaller(1);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to create new Credential. POST status: ' + status });
|
||||
});
|
||||
}
|
||||
else {
|
||||
var url = GetBasePath('credentials') + scope.id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.put(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
(base == 'credentials') ? ReturnToCaller() : ReturnToCaller(1);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to update Credential. PUT status: ' + status });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
if (Empty(data.team) && Empty(data.user)) {
|
||||
Alert('Missing User or Team', 'You must provide either a User or a Team. If this credential will only be accessed by a specific ' +
|
||||
'user, select a User. To allow a team of users to access this credential, select a Team.', 'alert-danger');
|
||||
} else {
|
||||
Wait('start');
|
||||
if (mode === 'add') {
|
||||
url = (!Empty(data.team)) ? GetBasePath('teams') + data.team + '/credentials/' :
|
||||
GetBasePath('users') + data.user + '/credentials/';
|
||||
Rest.setUrl(url);
|
||||
Rest.post(data)
|
||||
.success(function () {
|
||||
Wait('stop');
|
||||
var base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
if (base === 'credentials') {
|
||||
ReturnToCaller();
|
||||
}
|
||||
ReturnToCaller(1);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to create new Credential. POST status: ' + status
|
||||
});
|
||||
});
|
||||
} else {
|
||||
url = GetBasePath('credentials') + scope.id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.put(data)
|
||||
.success(function () {
|
||||
Wait('stop');
|
||||
var base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
if (base === 'credentials') {
|
||||
ReturnToCaller();
|
||||
}
|
||||
ReturnToCaller(1);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, form, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to update Credential. PUT status: ' + status
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -6,194 +6,57 @@
|
||||
* EventView - show the job_events form in a modal dialog
|
||||
*
|
||||
*/
|
||||
angular.module('EventsHelper', ['RestServices', 'Utilities', 'JobEventDataDefinition'])
|
||||
.factory('EventView', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GenerateForm',
|
||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'FormatDate', 'JobEventDataForm', 'Empty',
|
||||
function($rootScope, $location, $log, $routeParams, Rest, Alert, GenerateForm, Prompt, ProcessErrors, GetBasePath,
|
||||
FormatDate, JobEventDataForm, Empty) {
|
||||
return function(params) {
|
||||
|
||||
// We're going to manipulate the form object each time the user clicks on View button. We can't rely on what's
|
||||
// left of the form in memory each time. Instead we have to define the form from scratch, so for now we're
|
||||
// keeping it here inline rather than a separate file.
|
||||
//
|
||||
// Form manipulation is done to remove any empty values. In order for a section (or accordion) to not be drawn,
|
||||
// it needs to be removed prior to call jqueryui. Otherwise, attempting to hide accordion pieces after the
|
||||
// the accordion is rendered creates undesired behavior.
|
||||
var form = {
|
||||
name: 'job_events',
|
||||
well: false,
|
||||
forceListeners: true,
|
||||
fields: {
|
||||
status: {
|
||||
labelClass: 'job-\{\{ status \}\}',
|
||||
type: 'custom',
|
||||
section: 'Event',
|
||||
control: '<div class=\"job-event-status job-\{\{ status \}\}\"><i class=\"fa icon-job-{{ status }}"></i> \{\{ status \}\}</div>'
|
||||
},
|
||||
id: {
|
||||
label: 'ID',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Event',
|
||||
'class': 'span1'
|
||||
},
|
||||
created: {
|
||||
label: 'Created On',
|
||||
type: 'text',
|
||||
section: 'Event',
|
||||
readonly: true
|
||||
},
|
||||
host: {
|
||||
label: 'Host',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Event',
|
||||
ngShow: "host !== ''"
|
||||
},
|
||||
play: {
|
||||
label: 'Play',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Event',
|
||||
ngShow: "play !== ''"
|
||||
},
|
||||
task: {
|
||||
label: 'Task',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Event',
|
||||
ngShow: "task !== ''"
|
||||
},
|
||||
rc: {
|
||||
label: 'Return Code',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Results',
|
||||
'class': 'span1',
|
||||
ngShow: "rc !== ''"
|
||||
},
|
||||
msg: {
|
||||
label: 'Msg',
|
||||
type: 'textarea',
|
||||
readonly: true,
|
||||
section: 'Results',
|
||||
'class': 'nowrap',
|
||||
ngShow: "msg !== ''",
|
||||
rows: 10
|
||||
},
|
||||
stdout: {
|
||||
label: 'Std Out',
|
||||
type: 'textarea',
|
||||
readonly: true,
|
||||
section: 'Results',
|
||||
'class': 'nowrap',
|
||||
ngShow: "stdout !== ''",
|
||||
rows: 10
|
||||
},
|
||||
stderr: {
|
||||
label: 'Std Err',
|
||||
type: 'textarea',
|
||||
readonly: true,
|
||||
section: 'Results',
|
||||
'class': 'nowrap',
|
||||
ngShow: "stderr !== ''",
|
||||
rows: 10
|
||||
},
|
||||
results: {
|
||||
label: 'Results',
|
||||
type: 'textarea',
|
||||
section: 'Results',
|
||||
readonly: true,
|
||||
'class': 'nowrap',
|
||||
ngShow: "results !== ''",
|
||||
rows: 10
|
||||
},
|
||||
start: {
|
||||
label: 'Start',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Timing',
|
||||
ngShow: "start !== ''"
|
||||
},
|
||||
traceback: {
|
||||
label: false,
|
||||
type: 'textarea',
|
||||
readonly: true,
|
||||
section: 'Traceback',
|
||||
'class': 'nowrap',
|
||||
ngShow: "traceback !== ''",
|
||||
rows: 10
|
||||
},
|
||||
end: {
|
||||
label: 'End',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Timing',
|
||||
ngShow: "end !== ''"
|
||||
},
|
||||
delta: {
|
||||
label: 'Elapsed',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Timing',
|
||||
ngShow: "delta !== ''"
|
||||
},
|
||||
module_name: {
|
||||
label: 'Name',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Module',
|
||||
ngShow: "module_name !== ''"
|
||||
},
|
||||
module_args: {
|
||||
label: 'Args',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Module',
|
||||
ngShow: "module_args !== ''"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
'use strict';
|
||||
|
||||
var event_id = params.event_id;
|
||||
var generator = GenerateForm;
|
||||
var scope;
|
||||
var defaultUrl = GetBasePath('base') + 'job_events/' + event_id + '/';
|
||||
|
||||
// Retrieve detail record and prepopulate the form
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
|
||||
// If event_data is not available, remove fields that depend on it
|
||||
if ($.isEmptyObject(data['event_data']) || !data['event_data']['res'] || typeof data['event_data']['res'] == 'string') {
|
||||
for (var fld in form.fields) {
|
||||
switch(fld) {
|
||||
case 'start':
|
||||
case 'end':
|
||||
case 'delta':
|
||||
case 'msg':
|
||||
case 'stdout':
|
||||
case 'stderr':
|
||||
case 'msg':
|
||||
case 'results':
|
||||
case 'module_name':
|
||||
case 'module_args':
|
||||
case 'rc':
|
||||
delete form.fields[fld];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($.isEmptyObject(data['event_data']) || !data['event_data']['res'] || typeof data['event_data']['res'] != 'string') {
|
||||
delete form.fields['traceback'];
|
||||
}
|
||||
|
||||
// Remove remaining form fields that do not have a corresponding data value
|
||||
for (var fld in form.fields) {
|
||||
switch (fld) {
|
||||
angular.module('EventsHelper', ['RestServices', 'Utilities', 'JobEventDataDefinition', 'JobEventsFormDefinition'])
|
||||
|
||||
.factory('EventView', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GenerateForm',
|
||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'FormatDate', 'JobEventDataForm', 'Empty', 'JobEventsForm',
|
||||
function ($rootScope, $location, $log, $routeParams, Rest, Alert, GenerateForm, Prompt, ProcessErrors, GetBasePath,
|
||||
FormatDate, JobEventDataForm, Empty, JobEventsForm) {
|
||||
return function (params) {
|
||||
|
||||
var event_id = params.event_id,
|
||||
generator = GenerateForm,
|
||||
form = angular.copy(JobEventsForm),
|
||||
scope,
|
||||
defaultUrl = GetBasePath('base') + 'job_events/' + event_id + '/';
|
||||
|
||||
// Retrieve detail record and prepopulate the form
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
var i, n, fld, rows, txt, cDate;
|
||||
|
||||
// If event_data is not available, remove fields that depend on it
|
||||
if ($.isEmptyObject(data.event_data) || !data.event_data.res || typeof data.event_data.res === 'string') {
|
||||
for (fld in form.fields) {
|
||||
switch (fld) {
|
||||
case 'start':
|
||||
case 'end':
|
||||
case 'delta':
|
||||
case 'msg':
|
||||
case 'stdout':
|
||||
case 'stderr':
|
||||
case 'msg':
|
||||
case 'results':
|
||||
case 'module_name':
|
||||
case 'module_args':
|
||||
case 'rc':
|
||||
delete form.fields[fld];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($.isEmptyObject(data.event_data) || !data.event_data.res || typeof data.event_data.res !== 'string') {
|
||||
delete form.fields.traceback;
|
||||
}
|
||||
|
||||
// Remove remaining form fields that do not have a corresponding data value
|
||||
for (fld in form.fields) {
|
||||
switch (fld) {
|
||||
case 'start':
|
||||
case 'end':
|
||||
case 'delta':
|
||||
@ -202,114 +65,118 @@ angular.module('EventsHelper', ['RestServices', 'Utilities', 'JobEventDataDefini
|
||||
case 'stderr':
|
||||
case 'msg':
|
||||
case 'rc':
|
||||
if (data['event_data'] && data['event_data']['res'] && Empty(data['event_data']['res'][fld])) {
|
||||
delete form.fields[fld];
|
||||
}
|
||||
else {
|
||||
if (form.fields[fld].type == 'textarea') {
|
||||
var n = data['event_data']['res'][fld].match(/\n/g);
|
||||
var rows = (n) ? n.length : 1;
|
||||
rows = (rows > 10) ? 10 : rows;
|
||||
rows = (rows < 3) ? 3 : rows;
|
||||
form.fields[fld].rows = rows;
|
||||
}
|
||||
if (data.event_data && data.event_data.res && Empty(data.event_data.res[fld])) {
|
||||
delete form.fields[fld];
|
||||
} else {
|
||||
if (form.fields[fld].type === 'textarea') {
|
||||
n = data.event_data.res[fld].match(/\n/g);
|
||||
rows = (n) ? n.length : 1;
|
||||
rows = (rows > 10) ? 10 : rows;
|
||||
rows = (rows < 3) ? 3 : rows;
|
||||
form.fields[fld].rows = rows;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'results':
|
||||
if ( data['event_data'] && data['event_data']['res'] && data['event_data']['res'][fld] == undefined) {
|
||||
// not defined
|
||||
delete form.fields[fld];
|
||||
}
|
||||
else if (!Array.isArray(data['event_data']['res'][fld]) || data['event_data']['res'][fld].length == 0) {
|
||||
// defined, but empty
|
||||
delete form.fields[fld];
|
||||
}
|
||||
else {
|
||||
// defined and not empty, so attempt to size the textarea field
|
||||
var txt = '';
|
||||
for (var i=0; i < data['event_data']['res'][fld].length; i++) {
|
||||
txt += data['event_data']['res'][fld][i];
|
||||
}
|
||||
if (txt == '') {
|
||||
// there's an array, but the actual text is empty
|
||||
delete form.fields[fld];
|
||||
}
|
||||
else {
|
||||
var n = txt.match(/\n/g);
|
||||
var rows = (n) ? n.length : 1;
|
||||
rows = (rows > 10) ? 10 : rows;
|
||||
rows = (rows < 3) ? 3 : rows;
|
||||
form.fields[fld].rows = rows;
|
||||
}
|
||||
if (data.event_data && data.event_data.res && data.event_data.res[fld] === undefined) {
|
||||
// not defined
|
||||
delete form.fields[fld];
|
||||
} else if (!Array.isArray(data.event_data.res[fld]) || data.event_data.res[fld].length === 0) {
|
||||
// defined, but empty
|
||||
delete form.fields[fld];
|
||||
} else {
|
||||
// defined and not empty, so attempt to size the textarea field
|
||||
txt = '';
|
||||
for (i = 0; i < data.event_data.res[fld].length; i++) {
|
||||
txt += data.event_data.res[fld][i];
|
||||
}
|
||||
if (txt === '') {
|
||||
// there's an array, but the actual text is empty
|
||||
delete form.fields[fld];
|
||||
} else {
|
||||
n = txt.match(/\n/g);
|
||||
rows = (n) ? n.length : 1;
|
||||
rows = (rows > 10) ? 10 : rows;
|
||||
rows = (rows < 3) ? 3 : rows;
|
||||
form.fields[fld].rows = rows;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'module_name':
|
||||
case 'module_args':
|
||||
if (data['event_data'] && data['event_data']['res']) {
|
||||
if (data['event_data']['res']['invocation'] === undefined ||
|
||||
data['event_data']['res']['invocation'][fld] === undefined) {
|
||||
if (data.event_data && data.event_data.res) {
|
||||
if (data.event_data.res.invocation === undefined ||
|
||||
data.event_data.res.invocation[fld] === undefined) {
|
||||
delete form.fields[fld];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// load the form
|
||||
scope = generator.inject(form, { mode: 'edit', modal: true, related: false});
|
||||
generator.reset();
|
||||
scope.formModalAction = function() {
|
||||
$('#form-modal').modal("hide");
|
||||
}
|
||||
scope.formModalActionLabel = 'OK';
|
||||
scope.formModalCancelShow = false;
|
||||
scope.formModalInfo = 'View JSON';
|
||||
$('#form-modal .btn-success').removeClass('btn-success').addClass('btn-none');
|
||||
$('#form-modal').addClass('skinny-modal');
|
||||
scope.formModalHeader = data['event_display'].replace(/^\u00a0*/g,'');
|
||||
|
||||
// Respond to View JSON button
|
||||
scope.formModalInfoAction = function() {
|
||||
var generator = GenerateForm;
|
||||
var scope = generator.inject(JobEventDataForm, { mode: 'edit', modal: true, related: false,
|
||||
modal_selector: '#form-modal2', modal_body_id: 'form-modal2-body', modal_title_id: 'formModal2Header' });
|
||||
generator.reset();
|
||||
scope.formModal2Header = data['event_display'].replace(/^\u00a0*/g,'');
|
||||
scope.event_data = JSON.stringify(data['event_data'], null, '\t');
|
||||
scope.formModal2ActionLabel = 'OK';
|
||||
scope.formModal2CancelShow = false;
|
||||
scope.formModal2Info = false;
|
||||
scope.formModalInfo = 'View JSON';
|
||||
scope.formModal2Action = function() {
|
||||
$('#form-modal2').modal("hide");
|
||||
}
|
||||
$('#form-modal2 .btn-success').removeClass('btn-success').addClass('btn-none');
|
||||
}
|
||||
|
||||
if (typeof data['event_data']['res'] == 'string') {
|
||||
scope['traceback'] = data['event_data']['res'];
|
||||
}
|
||||
|
||||
for (var fld in form.fields) {
|
||||
switch(fld) {
|
||||
// load the form
|
||||
scope = generator.inject(form, {
|
||||
mode: 'edit',
|
||||
modal: true,
|
||||
related: false
|
||||
});
|
||||
generator.reset();
|
||||
scope.formModalAction = function () {
|
||||
$('#form-modal').modal("hide");
|
||||
};
|
||||
scope.formModalActionLabel = 'OK';
|
||||
scope.formModalCancelShow = false;
|
||||
scope.formModalInfo = 'View JSON';
|
||||
$('#form-modal .btn-success').removeClass('btn-success').addClass('btn-none');
|
||||
$('#form-modal').addClass('skinny-modal');
|
||||
scope.formModalHeader = data.event_display.replace(/^\u00a0*/g, '');
|
||||
|
||||
// Respond to View JSON button
|
||||
scope.formModalInfoAction = function () {
|
||||
var generator = GenerateForm,
|
||||
scope = generator.inject(JobEventDataForm, {
|
||||
mode: 'edit',
|
||||
modal: true,
|
||||
related: false,
|
||||
modal_selector: '#form-modal2',
|
||||
modal_body_id: 'form-modal2-body',
|
||||
modal_title_id: 'formModal2Header'
|
||||
});
|
||||
generator.reset();
|
||||
scope.formModal2Header = data.event_display.replace(/^\u00a0*/g, '');
|
||||
scope.event_data = JSON.stringify(data.event_data, null, '\t');
|
||||
scope.formModal2ActionLabel = 'OK';
|
||||
scope.formModal2CancelShow = false;
|
||||
scope.formModal2Info = false;
|
||||
scope.formModalInfo = 'View JSON';
|
||||
scope.formModal2Action = function () {
|
||||
$('#form-modal2').modal("hide");
|
||||
};
|
||||
$('#form-modal2 .btn-success').removeClass('btn-success').addClass('btn-none');
|
||||
};
|
||||
|
||||
if (typeof data.event_data.res === 'string') {
|
||||
scope.traceback = data.event_data.res;
|
||||
}
|
||||
|
||||
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';
|
||||
if (data.failed) {
|
||||
scope.status = 'error';
|
||||
} else if (data.changed) {
|
||||
scope.status = 'changed';
|
||||
} else {
|
||||
scope.status = 'success';
|
||||
}
|
||||
break;
|
||||
case 'created':
|
||||
var cDate = new Date(data['created']);
|
||||
scope['created'] = FormatDate(cDate);
|
||||
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'];
|
||||
if (data.summary_fields && data.summary_fields.host) {
|
||||
scope.host = data.summary_fields.host.name;
|
||||
}
|
||||
break;
|
||||
case 'id':
|
||||
@ -319,50 +186,50 @@ angular.module('EventsHelper', ['RestServices', 'Utilities', 'JobEventDataDefini
|
||||
break;
|
||||
case 'start':
|
||||
case 'end':
|
||||
if (data['event_data'] && data['event_data']['res'] && !Empty(data['event_data']['res'][fld])) {
|
||||
scope[fld] = data['event_data']['res'][fld];
|
||||
if (data.event_data && data.event_data.res && !Empty(data.event_data.res[fld])) {
|
||||
scope[fld] = data.event_data.res[fld];
|
||||
}
|
||||
|
||||
break;
|
||||
case 'results':
|
||||
if (Array.isArray(data['event_data']['res'][fld]) && data['event_data']['res'][fld].length > 0 ) {
|
||||
var txt = '';
|
||||
for (var i=0; i < data['event_data']['res'][fld].length; i++) {
|
||||
txt += data['event_data']['res'][fld][i];
|
||||
}
|
||||
if (txt !== '') {
|
||||
scope[fld] = txt;
|
||||
}
|
||||
case 'results':
|
||||
if (Array.isArray(data.event_data.res[fld]) && data.event_data.res[fld].length > 0) {
|
||||
txt = '';
|
||||
for (i = 0; i < data.event_data.res[fld].length; i++) {
|
||||
txt += data.event_data.res[fld][i];
|
||||
}
|
||||
if (txt !== '') {
|
||||
scope[fld] = txt;
|
||||
}
|
||||
}
|
||||
break;
|
||||
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 (data.event_data && data.event_data.res && data.event_data.res[fld] !== undefined) {
|
||||
scope[fld] = data.event_data.res[fld];
|
||||
}
|
||||
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];
|
||||
if (data.event_data.res && data.event_data.res.invocation) {
|
||||
scope[fld] = data.event_data.res.invocation[fld];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!scope.$$phase) {
|
||||
scope.$digest();
|
||||
}
|
||||
}
|
||||
|
||||
if (!scope.$$phase) {
|
||||
scope.$digest();
|
||||
}
|
||||
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
$('#form-modal').modal("hide");
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to retrieve event: ' + event_id + '. GET status: ' + status });
|
||||
.error(function (data, status) {
|
||||
$('#form-modal').modal("hide");
|
||||
ProcessErrors(scope, data, status, form, { hdr: 'Error!',
|
||||
msg: 'Failed to retrieve event: ' + event_id + '. GET status: ' + status });
|
||||
});
|
||||
|
||||
}
|
||||
}]);
|
||||
};
|
||||
}
|
||||
]);
|
||||
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,8 @@
|
||||
|
||||
/* jshint loopfunc: true */
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'HostListDefinition',
|
||||
'SearchHelper', 'PaginationHelpers', 'ListGenerator', 'AuthService', 'HostsHelper',
|
||||
'InventoryHelper', 'RelatedSearchHelper', 'InventoryFormDefinition', 'SelectionHelper',
|
||||
|
||||
@ -2,479 +2,463 @@
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* JobSubmission.js
|
||||
*
|
||||
*
|
||||
*/
|
||||
angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'CredentialFormDefinition', 'CredentialsListDefinition',
|
||||
'LookUpHelper', 'ProjectFormDefinition', 'JobSubmissionHelper' ])
|
||||
|
||||
.factory('PromptPasswords', ['CredentialForm', 'JobTemplateForm', '$compile', 'Rest', '$location', 'ProcessErrors',
|
||||
'GetBasePath', 'Alert', 'Empty', 'Wait',
|
||||
function(CredentialForm, JobTemplateForm, $compile, Rest, $location, ProcessErrors, GetBasePath, Alert, Empty, Wait) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var passwords = params.passwords;
|
||||
var start_url = params.start_url;
|
||||
var form = params.form;
|
||||
var html = '';
|
||||
var field, element, dialogScope, fld;
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
var extra_html = params.extra_html;
|
||||
'use strict';
|
||||
|
||||
function navigate(canceled) {
|
||||
//Decide where to send the user once the modal dialog closes
|
||||
if (!canceled) {
|
||||
if (base == 'jobs') {
|
||||
scope.refreshJob();
|
||||
}
|
||||
else {
|
||||
$location.path('/jobs');
|
||||
}
|
||||
}
|
||||
else {
|
||||
$location.path('/' + base);
|
||||
}
|
||||
}
|
||||
angular.module('JobSubmissionHelper', ['RestServices', 'Utilities', 'CredentialFormDefinition', 'CredentialsListDefinition',
|
||||
'LookUpHelper', 'ProjectFormDefinition', 'JobSubmissionHelper'
|
||||
])
|
||||
|
||||
function cancel() {
|
||||
// Delete a job
|
||||
var url = GetBasePath('jobs') + scope.job_id +'/'
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success ( function(data, status, headers, config) {
|
||||
if (form.name == 'credential') {
|
||||
navigate(true);
|
||||
.factory('PromptPasswords', ['CredentialForm', 'JobTemplateForm', '$compile', 'Rest', '$location', 'ProcessErrors',
|
||||
'GetBasePath', 'Alert', 'Empty', 'Wait',
|
||||
function (CredentialForm, JobTemplateForm, $compile, Rest, $location, ProcessErrors, GetBasePath, Alert, Empty, Wait) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
passwords = params.passwords,
|
||||
start_url = params.start_url,
|
||||
form = params.form,
|
||||
html = '',
|
||||
field, element, fld, i, current_form,
|
||||
base = $location.path().replace(/^\//, '').split('/')[0],
|
||||
extra_html = params.extra_html;
|
||||
|
||||
function navigate(canceled) {
|
||||
//Decide where to send the user once the modal dialog closes
|
||||
if (!canceled) {
|
||||
if (base === 'jobs') {
|
||||
scope.refreshJob();
|
||||
} else {
|
||||
$location.path('/jobs');
|
||||
}
|
||||
} else {
|
||||
$location.path('/' + base);
|
||||
}
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
// Delete a job
|
||||
var url = GetBasePath('jobs') + scope.job_id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.destroy()
|
||||
.success(function () {
|
||||
if (form.name === 'credential') {
|
||||
navigate(true);
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
||||
});
|
||||
}
|
||||
|
||||
scope.cancelJob = function() {
|
||||
// User clicked cancel button
|
||||
$('#password-modal').modal('hide');
|
||||
if (form.name == 'credential') {
|
||||
cancel();
|
||||
}
|
||||
else {
|
||||
scope.$emit('UpdateSubmitted','canceled');
|
||||
}
|
||||
}
|
||||
|
||||
scope.startJob = function() {
|
||||
$('#password-modal').modal('hide');
|
||||
Wait('start');
|
||||
var pswd = {};
|
||||
var value_supplied = false;
|
||||
$('.password-field').each(function(index) {
|
||||
pswd[$(this).attr('name')] = $(this).val();
|
||||
if ($(this).val() != '' && $(this).val() !== null) {
|
||||
value_supplied = true;
|
||||
scope.cancelJob = function () {
|
||||
// User clicked cancel button
|
||||
$('#password-modal').modal('hide');
|
||||
if (form.name === 'credential') {
|
||||
cancel();
|
||||
} else {
|
||||
scope.$emit('UpdateSubmitted', 'canceled');
|
||||
}
|
||||
});
|
||||
if (Empty(passwords) || passwords.length == 0 || value_supplied) {
|
||||
Rest.setUrl(start_url);
|
||||
Rest.post(pswd)
|
||||
.success( function(data, status, headers, config) {
|
||||
scope.$emit('UpdateSubmitted','started');
|
||||
if (form.name == 'credential') {
|
||||
navigate(false);
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'POST to ' + start_url + ' failed with status: ' + status });
|
||||
});
|
||||
}
|
||||
else {
|
||||
Wait('stop');
|
||||
Alert('No Passwords', 'Required password(s) not provided. The request was not submitted.', 'alert-info');
|
||||
if (form.name == 'credential') {
|
||||
// No passwords provided, so we can't start the job. Rather than leave the job in a 'new'
|
||||
// state, let's delete it.
|
||||
cancelJob();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (passwords && passwords.length > 0) {
|
||||
Wait('stop');
|
||||
// Prompt for passwords
|
||||
html += "<form class=\"form-horizontal\" name=\"password_form\" novalidate>\n";
|
||||
html += (extra_html) ? extra_html : "";
|
||||
var current_form;
|
||||
for (var i=0; i < passwords.length; i++) {
|
||||
// Add the password field
|
||||
if (form.name == 'credential') {
|
||||
// this is a job. we could be prompting for inventory and/or SCM passwords
|
||||
if (form.fields[passwords[i]]) {
|
||||
current_form = form;
|
||||
}
|
||||
/*
|
||||
else if (ProjectsForm.fields[passwords[i]]) {
|
||||
current_form = ProjectsForm;
|
||||
}
|
||||
else if (GroupForm.fields[passwords[i]]) {
|
||||
current_form = GroupForm;
|
||||
}
|
||||
*/
|
||||
else {
|
||||
// No match found. Abandon ship!
|
||||
Alert('Form Not Found', 'Could not locate form for: ' + passwords[i], 'alert-danger');
|
||||
$location('/#/jobs');
|
||||
}
|
||||
}
|
||||
else {
|
||||
current_form = form;
|
||||
}
|
||||
field = current_form.fields[passwords[i]];
|
||||
fld = passwords[i];
|
||||
scope[fld] = '';
|
||||
html += "<div class=\"form-group\">\n";
|
||||
html += "<label class=\"control-label col-lg-3 normal-weight\" for=\"" + fld + "\">* ";
|
||||
html += (field.labelBind) ? scope[field.labelBind] : field.label;
|
||||
html += "</label>\n";
|
||||
html += "<div class=\"col-lg-9\">\n";
|
||||
html += "<input type=\"password\" ";
|
||||
html += "ng-model=\"" + fld + '" ';
|
||||
html += 'name="' + fld + '" ';
|
||||
html += "class=\"password-field form-control\" ";
|
||||
html += "required ";
|
||||
html += "/>";
|
||||
html += "<br />\n";
|
||||
// Add error messages
|
||||
html += "<span class=\"error\" ng-show=\"password_form." + fld + ".$dirty && " +
|
||||
"password_form." + fld + ".$error.required\">A value is required!</span>\n";
|
||||
html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
|
||||
// Add the related confirm field
|
||||
fld = field.associated;
|
||||
field = current_form.fields[field.associated];
|
||||
scope[fld] = '';
|
||||
html += "<div class=\"form-group\">\n";
|
||||
html += "<label class=\"control-label col-lg-3 normal-weight\" for=\"" + fld + "\">* ";
|
||||
html += (field.labelBind) ? scope[field.labelBind] : field.label;
|
||||
html += "</label>\n";
|
||||
html += "<div class=\"col-lg-9\">\n";
|
||||
html += "<input type=\"password\" ";
|
||||
html += "ng-model=\"" + fld + '" ';
|
||||
html += 'name="' + fld + '" ';
|
||||
html += "class=\"form-control\" ";
|
||||
html += "required ";
|
||||
html += (field.awPassMatch) ? "awpassmatch=\"" + field.associated + "\" " : "";
|
||||
html += "/>";
|
||||
html += "<br />\n";
|
||||
// Add error messages
|
||||
html += "<span class=\"error\" ng-show=\"password_form." + fld + ".$dirty && " +
|
||||
"password_form." + fld + ".$error.required\">A value is required!</span>\n";
|
||||
if (field.awPassMatch) {
|
||||
html += "<span class=\"error\" ng-show=\"password_form." + fld +
|
||||
".$error.awpassmatch\">Must match Password value</span>\n";
|
||||
}
|
||||
html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
}
|
||||
html += "</form>\n";
|
||||
var element = angular.element(document.getElementById('password-body'));
|
||||
element.html(html);
|
||||
$compile(element.contents())(scope);
|
||||
$('#password-modal').modal();
|
||||
$('#password-modal').on('shown.bs.modal', function() {
|
||||
$('#password-body').find('input[type="password"]:first').focus();
|
||||
});
|
||||
}
|
||||
else {
|
||||
scope.startJob();
|
||||
}
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('SubmitJob',['PromptPasswords', '$compile', 'Rest', '$location', 'GetBasePath', 'CredentialList',
|
||||
'LookUpInit', 'CredentialForm', 'ProcessErrors', 'JobTemplateForm', 'Wait',
|
||||
function(PromptPasswords, $compile, Rest, $location, GetBasePath, CredentialList, LookUpInit, CredentialForm,
|
||||
ProcessErrors, JobTemplateForm, Wait) {
|
||||
return function(params) {
|
||||
var scope = params.scope;
|
||||
var id = params.id;
|
||||
var template_name = (params.template) ? params.template : null;
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
var url = GetBasePath(base) + id + '/';
|
||||
};
|
||||
|
||||
function postJob(data) {
|
||||
// Create the job record
|
||||
if (scope.credentialWatchRemove) {
|
||||
scope.credentialWatchRemove();
|
||||
scope.startJob = function () {
|
||||
var pswd = {}, value_supplied = false;
|
||||
$('#password-modal').modal('hide');
|
||||
Wait('start');
|
||||
$('.password-field').each(function () {
|
||||
pswd[$(this).attr('name')] = $(this).val();
|
||||
if ($(this).val() !== '' && $(this).val() !== null) {
|
||||
value_supplied = true;
|
||||
}
|
||||
});
|
||||
if (Empty(passwords) || passwords.length === 0 || value_supplied) {
|
||||
Rest.setUrl(start_url);
|
||||
Rest.post(pswd)
|
||||
.success(function () {
|
||||
scope.$emit('UpdateSubmitted', 'started');
|
||||
if (form.name === 'credential') {
|
||||
navigate(false);
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'POST to ' + start_url + ' failed with status: ' + status });
|
||||
});
|
||||
} else {
|
||||
Wait('stop');
|
||||
Alert('No Passwords', 'Required password(s) not provided. The request was not submitted.', 'alert-info');
|
||||
if (form.name === 'credential') {
|
||||
// No passwords provided, so we can't start the job. Rather than leave the job in a 'new'
|
||||
// state, let's delete it.
|
||||
scope.cancelJob();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (passwords && passwords.length > 0) {
|
||||
Wait('stop');
|
||||
// Prompt for passwords
|
||||
html += "<form class=\"form-horizontal\" name=\"password_form\" novalidate>\n";
|
||||
html += (extra_html) ? extra_html : "";
|
||||
for (i = 0; i < passwords.length; i++) {
|
||||
// Add the password field
|
||||
if (form.name === 'credential') {
|
||||
// this is a job. we could be prompting for inventory and/or SCM passwords
|
||||
if (form.fields[passwords[i]]) {
|
||||
current_form = form;
|
||||
}
|
||||
else {
|
||||
// No match found. Abandon ship!
|
||||
Alert('Form Not Found', 'Could not locate form for: ' + passwords[i], 'alert-danger');
|
||||
$location('/#/jobs');
|
||||
}
|
||||
} else {
|
||||
current_form = form;
|
||||
}
|
||||
field = current_form.fields[passwords[i]];
|
||||
fld = passwords[i];
|
||||
scope[fld] = '';
|
||||
html += "<div class=\"form-group\">\n";
|
||||
html += "<label class=\"control-label col-lg-3 normal-weight\" for=\"" + fld + "\">* ";
|
||||
html += (field.labelBind) ? scope[field.labelBind] : field.label;
|
||||
html += "</label>\n";
|
||||
html += "<div class=\"col-lg-9\">\n";
|
||||
html += "<input type=\"password\" ";
|
||||
html += "ng-model=\"" + fld + '" ';
|
||||
html += 'name="' + fld + '" ';
|
||||
html += "class=\"password-field form-control\" ";
|
||||
html += "required ";
|
||||
html += "/>";
|
||||
html += "<br />\n";
|
||||
// Add error messages
|
||||
html += "<span class=\"error\" ng-show=\"password_form." + fld + ".$dirty && " +
|
||||
"password_form." + fld + ".$error.required\">A value is required!</span>\n";
|
||||
html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
|
||||
// Add the related confirm field
|
||||
fld = field.associated;
|
||||
field = current_form.fields[field.associated];
|
||||
scope[fld] = '';
|
||||
html += "<div class=\"form-group\">\n";
|
||||
html += "<label class=\"control-label col-lg-3 normal-weight\" for=\"" + fld + "\">* ";
|
||||
html += (field.labelBind) ? scope[field.labelBind] : field.label;
|
||||
html += "</label>\n";
|
||||
html += "<div class=\"col-lg-9\">\n";
|
||||
html += "<input type=\"password\" ";
|
||||
html += "ng-model=\"" + fld + '" ';
|
||||
html += 'name="' + fld + '" ';
|
||||
html += "class=\"form-control\" ";
|
||||
html += "required ";
|
||||
html += (field.awPassMatch) ? "awpassmatch=\"" + field.associated + "\" " : "";
|
||||
html += "/>";
|
||||
html += "<br />\n";
|
||||
// Add error messages
|
||||
html += "<span class=\"error\" ng-show=\"password_form." + fld + ".$dirty && " +
|
||||
"password_form." + fld + ".$error.required\">A value is required!</span>\n";
|
||||
if (field.awPassMatch) {
|
||||
html += "<span class=\"error\" ng-show=\"password_form." + fld +
|
||||
".$error.awpassmatch\">Must match Password value</span>\n";
|
||||
}
|
||||
html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
}
|
||||
html += "</form>\n";
|
||||
element = angular.element(document.getElementById('password-body'));
|
||||
element.html(html);
|
||||
$compile(element.contents())(scope);
|
||||
$('#password-modal').modal();
|
||||
$('#password-modal').on('shown.bs.modal', function () {
|
||||
$('#password-body').find('input[type="password"]:first').focus();
|
||||
});
|
||||
} else {
|
||||
scope.startJob();
|
||||
}
|
||||
var dt = new Date().toISOString();
|
||||
var url = (data.related.jobs) ? data.related.jobs : data.related.job_template + 'jobs/';
|
||||
var name = (template_name) ? template_name : data.name;
|
||||
Wait('start');
|
||||
Rest.setUrl(url);
|
||||
Rest.post({
|
||||
name: name + ' ' + dt, // job name required and unique
|
||||
description: data.description,
|
||||
job_template: data.id,
|
||||
inventory: data.inventory,
|
||||
project: data.project,
|
||||
playbook: data.playbook,
|
||||
credential: data.credential,
|
||||
forks: data.forks,
|
||||
limit: data.limit,
|
||||
verbosity: data.verbosity,
|
||||
extra_vars: data.extra_vars
|
||||
})
|
||||
.success( function(data, status, headers, config) {
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
.factory('SubmitJob', ['PromptPasswords', '$compile', 'Rest', '$location', 'GetBasePath', 'CredentialList',
|
||||
'LookUpInit', 'CredentialForm', 'ProcessErrors', 'JobTemplateForm', 'Wait',
|
||||
function (PromptPasswords, $compile, Rest, $location, GetBasePath, CredentialList, LookUpInit, CredentialForm,
|
||||
ProcessErrors, JobTemplateForm, Wait) {
|
||||
return function (params) {
|
||||
var scope = params.scope,
|
||||
id = params.id,
|
||||
template_name = (params.template) ? params.template : null,
|
||||
base = $location.path().replace(/^\//, '').split('/')[0],
|
||||
url = GetBasePath(base) + id + '/';
|
||||
|
||||
function postJob(data) {
|
||||
var dt, url, name;
|
||||
// Create the job record
|
||||
if (scope.credentialWatchRemove) {
|
||||
scope.credentialWatchRemove();
|
||||
}
|
||||
dt = new Date().toISOString();
|
||||
url = (data.related.jobs) ? data.related.jobs : data.related.job_template + 'jobs/';
|
||||
name = (template_name) ? template_name : data.name;
|
||||
Wait('start');
|
||||
Rest.setUrl(url);
|
||||
Rest.post({
|
||||
name: name + ' ' + dt, // job name required and unique
|
||||
description: data.description,
|
||||
job_template: data.id,
|
||||
inventory: data.inventory,
|
||||
project: data.project,
|
||||
playbook: data.playbook,
|
||||
credential: data.credential,
|
||||
forks: data.forks,
|
||||
limit: data.limit,
|
||||
verbosity: data.verbosity,
|
||||
extra_vars: data.extra_vars
|
||||
}).success(function (data) {
|
||||
scope.job_id = data.id;
|
||||
if (data.passwords_needed_to_start.length > 0) {
|
||||
// Passwords needed. Prompt for passwords, then start job.
|
||||
PromptPasswords({
|
||||
scope: scope,
|
||||
passwords: data.passwords_needed_to_start,
|
||||
start_url: data.related.start,
|
||||
form: CredentialForm
|
||||
});
|
||||
// Passwords needed. Prompt for passwords, then start job.
|
||||
PromptPasswords({
|
||||
scope: scope,
|
||||
passwords: data.passwords_needed_to_start,
|
||||
start_url: data.related.start,
|
||||
form: CredentialForm
|
||||
});
|
||||
} else {
|
||||
// No passwords needed, start the job!
|
||||
Rest.setUrl(data.related.start);
|
||||
Rest.post()
|
||||
.success(function () {
|
||||
Wait('stop');
|
||||
var base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
if (base === 'jobs') {
|
||||
scope.refresh();
|
||||
} else {
|
||||
$location.path('/jobs');
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to start job. POST returned status: ' + status });
|
||||
});
|
||||
}
|
||||
else {
|
||||
// No passwords needed, start the job!
|
||||
Rest.setUrl(data.related.start);
|
||||
Rest.post()
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
if (base == 'jobs') {
|
||||
scope.refresh();
|
||||
}
|
||||
else {
|
||||
$location.path('/jobs');
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to start job. POST returned status: ' + status });
|
||||
});
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
}).error(function (data, status) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to create job. POST returned status: ' + status });
|
||||
});
|
||||
};
|
||||
|
||||
// Get the job or job_template record
|
||||
Wait('start');
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
// Create a job record
|
||||
scope.credential = '';
|
||||
if (data.credential == '' || data.credential == null) {
|
||||
// Template does not have credential, prompt for one
|
||||
Wait('stop');
|
||||
if (scope.credentialWatchRemove) {
|
||||
scope.credentialWatchRemove();
|
||||
}
|
||||
scope.credentialWatchRemove = scope.$watch('credential', function(newVal, oldVal) {
|
||||
if (newVal !== oldVal) {
|
||||
// After user selects a credential from the modal,
|
||||
// submit the job
|
||||
if (scope.credential != '' && scope.credential !== null && scope.credential !== undefined) {
|
||||
data.credential = scope.credential;
|
||||
postJob(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
LookUpInit({
|
||||
scope: scope,
|
||||
form: JobTemplateForm,
|
||||
current_item: null,
|
||||
list: CredentialList,
|
||||
field: 'credential',
|
||||
hdr: 'Credential Required'
|
||||
});
|
||||
scope.lookUpCredential();
|
||||
}
|
||||
else {
|
||||
// We have what we need, submit the job
|
||||
postJob(data);
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to get job template details. GET returned status: ' + status });
|
||||
});
|
||||
};
|
||||
}])
|
||||
|
||||
// Sumbit SCM Update request
|
||||
.factory('ProjectUpdate',['PromptPasswords', '$compile', 'Rest', '$location', 'GetBasePath', 'ProcessErrors', 'Alert',
|
||||
'ProjectsForm', 'Wait',
|
||||
function(PromptPasswords, $compile, Rest, $location, GetBasePath, ProcessErrors, Alert, ProjectsForm, Wait) {
|
||||
return function(params) {
|
||||
var scope = params.scope;
|
||||
var project_id = params.project_id;
|
||||
var url = GetBasePath('projects') + project_id + '/update/';
|
||||
|
||||
if (scope.removeUpdateSubmitted) {
|
||||
scope.removeUpdateSubmitted();
|
||||
}
|
||||
scope.removeUpdateSubmitted = scope.$on('UpdateSubmitted', function(e, action) {
|
||||
// Refresh the project list after update request submitted
|
||||
Wait('stop');
|
||||
Alert('Update Started', 'The request to start the SCM update process was submitted. ' +
|
||||
'To monitor the update status, refresh the page by clicking the <em>Refresh</em> button.', 'alert-info');
|
||||
scope.refresh();
|
||||
});
|
||||
|
||||
if (scope.removeSCMSubmit) {
|
||||
scope.removeSCMSubmit();
|
||||
}
|
||||
scope.removeSCMSubmit = scope.$on('SCMSubmit', function(e, passwords_needed_to_update, extra_html) {
|
||||
// After the call to update, kick off the job.
|
||||
PromptPasswords({
|
||||
scope: scope,
|
||||
passwords: passwords_needed_to_update,
|
||||
start_url: url,
|
||||
form: ProjectsForm,
|
||||
extra_html: extra_html
|
||||
});
|
||||
});
|
||||
|
||||
// Check to see if we have permission to perform the update and if any passwords are needed
|
||||
Wait('start');
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to create job. POST returned status: ' + status });
|
||||
});
|
||||
}
|
||||
|
||||
// Get the job or job_template record
|
||||
Wait('start');
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
// Create a job record
|
||||
scope.credential = '';
|
||||
if (data.credential === '' || data.credential === null) {
|
||||
// Template does not have credential, prompt for one
|
||||
Wait('stop');
|
||||
if (scope.credentialWatchRemove) {
|
||||
scope.credentialWatchRemove();
|
||||
}
|
||||
scope.credentialWatchRemove = scope.$watch('credential', function (newVal, oldVal) {
|
||||
if (newVal !== oldVal) {
|
||||
// After user selects a credential from the modal,
|
||||
// submit the job
|
||||
if (scope.credential !== '' && scope.credential !== null && scope.credential !== undefined) {
|
||||
data.credential = scope.credential;
|
||||
postJob(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
LookUpInit({
|
||||
scope: scope,
|
||||
form: JobTemplateForm,
|
||||
current_item: null,
|
||||
list: CredentialList,
|
||||
field: 'credential',
|
||||
hdr: 'Credential Required'
|
||||
});
|
||||
scope.lookUpCredential();
|
||||
} else {
|
||||
// We have what we need, submit the job
|
||||
postJob(data);
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to get job template details. GET returned status: ' + status });
|
||||
});
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
// Sumbit SCM Update request
|
||||
.factory('ProjectUpdate', ['PromptPasswords', '$compile', 'Rest', '$location', 'GetBasePath', 'ProcessErrors', 'Alert',
|
||||
'ProjectsForm', 'Wait',
|
||||
function (PromptPasswords, $compile, Rest, $location, GetBasePath, ProcessErrors, Alert, ProjectsForm, Wait) {
|
||||
return function (params) {
|
||||
var scope = params.scope,
|
||||
project_id = params.project_id,
|
||||
url = GetBasePath('projects') + project_id + '/update/';
|
||||
|
||||
if (scope.removeUpdateSubmitted) {
|
||||
scope.removeUpdateSubmitted();
|
||||
}
|
||||
scope.removeUpdateSubmitted = scope.$on('UpdateSubmitted', function () {
|
||||
// Refresh the project list after update request submitted
|
||||
Wait('stop');
|
||||
if (data.can_update) {
|
||||
var extra_html = '';
|
||||
for (var i=0; i < scope.projects.length; i++) {
|
||||
if (scope.projects[i].id == project_id) {
|
||||
extra_html += "<div class=\"form-group\">\n";
|
||||
extra_html += "<label class=\"control-label col-lg-3 normal-weight\" for=\"scm_url\">SCM URL</label>\n";
|
||||
extra_html += "<div class=\"col-lg-9\">\n";
|
||||
extra_html += "<input type=\"text\" readonly";
|
||||
extra_html += ' name=\"scm_url\" ';
|
||||
extra_html += "class=\"form-control\" ";
|
||||
extra_html += "value=\"" + scope.projects[i].scm_url + "\" ";
|
||||
extra_html += "/>";
|
||||
extra_html += "</div>\n";
|
||||
extra_html += "</div>\n";
|
||||
if (scope.projects[i].scm_username) {
|
||||
extra_html += "<div class=\"form-group\">\n";
|
||||
extra_html += "<label class=\"control-label col-lg-3 normal-weight\" for=\"scm_username\">SCM Username</label>\n";
|
||||
extra_html += "<div class=\"col-lg-9\">\n";
|
||||
extra_html += "<input type=\"text\" readonly";
|
||||
extra_html += ' name=\"scm_username\" ';
|
||||
extra_html += "class=\"form-control\" ";
|
||||
extra_html += "value=\"" + scope.projects[i].scm_username + "\" ";
|
||||
extra_html += "/>";
|
||||
extra_html += "</div>\n";
|
||||
extra_html += "</div>\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
extra_html += "</p>";
|
||||
scope.$emit('SCMSubmit', data.passwords_needed_to_update, extra_html);
|
||||
}
|
||||
else {
|
||||
Alert('Permission Denied', 'You do not have access to update this project. Please contact your system administrator.',
|
||||
'alert-danger');
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to get project update details: ' + url + ' GET status: ' + status });
|
||||
Alert('Update Started', 'The request to start the SCM update process was submitted. ' +
|
||||
'To monitor the update status, refresh the page by clicking the <em>Refresh</em> button.', 'alert-info');
|
||||
scope.refresh();
|
||||
});
|
||||
};
|
||||
}])
|
||||
|
||||
if (scope.removeSCMSubmit) {
|
||||
scope.removeSCMSubmit();
|
||||
}
|
||||
scope.removeSCMSubmit = scope.$on('SCMSubmit', function (e, passwords_needed_to_update, extra_html) {
|
||||
// After the call to update, kick off the job.
|
||||
PromptPasswords({
|
||||
scope: scope,
|
||||
passwords: passwords_needed_to_update,
|
||||
start_url: url,
|
||||
form: ProjectsForm,
|
||||
extra_html: extra_html
|
||||
});
|
||||
});
|
||||
|
||||
// Check to see if we have permission to perform the update and if any passwords are needed
|
||||
Wait('start');
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
var i, extra_html;
|
||||
Wait('stop');
|
||||
if (data.can_update) {
|
||||
extra_html = '';
|
||||
for (i = 0; i < scope.projects.length; i++) {
|
||||
if (scope.projects[i].id === project_id) {
|
||||
extra_html += "<div class=\"form-group\">\n";
|
||||
extra_html += "<label class=\"control-label col-lg-3 normal-weight\" for=\"scm_url\">SCM URL</label>\n";
|
||||
extra_html += "<div class=\"col-lg-9\">\n";
|
||||
extra_html += "<input type=\"text\" readonly";
|
||||
extra_html += ' name=\"scm_url\" ';
|
||||
extra_html += "class=\"form-control\" ";
|
||||
extra_html += "value=\"" + scope.projects[i].scm_url + "\" ";
|
||||
extra_html += "/>";
|
||||
extra_html += "</div>\n";
|
||||
extra_html += "</div>\n";
|
||||
if (scope.projects[i].scm_username) {
|
||||
extra_html += "<div class=\"form-group\">\n";
|
||||
extra_html += "<label class=\"control-label col-lg-3 normal-weight\" for=\"scm_username\">SCM Username</label>\n";
|
||||
extra_html += "<div class=\"col-lg-9\">\n";
|
||||
extra_html += "<input type=\"text\" readonly";
|
||||
extra_html += ' name=\"scm_username\" ';
|
||||
extra_html += "class=\"form-control\" ";
|
||||
extra_html += "value=\"" + scope.projects[i].scm_username + "\" ";
|
||||
extra_html += "/>";
|
||||
extra_html += "</div>\n";
|
||||
extra_html += "</div>\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
extra_html += "</p>";
|
||||
scope.$emit('SCMSubmit', data.passwords_needed_to_update, extra_html);
|
||||
} else {
|
||||
Alert('Permission Denied', 'You do not have access to update this project. Please contact your system administrator.',
|
||||
'alert-danger');
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to get project update details: ' + url + ' GET status: ' + status
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
// Sumbit Inventory Update request
|
||||
.factory('InventoryUpdate',['PromptPasswords', '$compile', 'Rest', '$location', 'GetBasePath', 'ProcessErrors', 'Alert',
|
||||
'GroupForm', 'BuildTree', 'Wait',
|
||||
function(PromptPasswords, $compile, Rest, $location, GetBasePath, ProcessErrors, Alert, GroupForm, BuildTree, Wait) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var inventory_id = params.inventory_id;
|
||||
var url = params.url;
|
||||
var group_name = params.group_name;
|
||||
var group_source = params.group_source;
|
||||
var group_id = params.group_id;
|
||||
var tree_id = params.tree_id;
|
||||
// Sumbit Inventory Update request
|
||||
.factory('InventoryUpdate', ['PromptPasswords', '$compile', 'Rest', '$location', 'GetBasePath', 'ProcessErrors', 'Alert',
|
||||
'GroupForm', 'BuildTree', 'Wait',
|
||||
function (PromptPasswords, $compile, Rest, $location, GetBasePath, ProcessErrors, Alert, GroupForm, BuildTree, Wait) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
url = params.url,
|
||||
group_id = params.group_id,
|
||||
tree_id = params.tree_id;
|
||||
|
||||
if (scope.removeHostReloadComplete) {
|
||||
scope.removeHostReloadComplete();
|
||||
}
|
||||
scope.removeHostReloadComplete = scope.$on('HostReloadComplete', function(e) {
|
||||
Wait('stop');
|
||||
Alert('Update Started', 'Your request to start the inventory sync process was submitted. Monitor progress ' +
|
||||
'by clicking the <i class="fa fa-refresh fa-lg"></i> button.', 'alert-info');
|
||||
if (scope.removeHostReloadComplete) {
|
||||
scope.removeHostReloadComplete();
|
||||
}
|
||||
});
|
||||
|
||||
if (scope.removeUpdateSubmitted) {
|
||||
scope.removeUpdateSubmitted();
|
||||
}
|
||||
scope.removeUpdateSubmitted = scope.$on('UpdateSubmitted', function(e, action) {
|
||||
if (action == 'started') {
|
||||
if (scope.refreshGroups) {
|
||||
scope.selected_tree_id = tree_id;
|
||||
scope.selected_group_id = group_id;
|
||||
scope.refreshGroups();
|
||||
}
|
||||
else if (scope.refresh) {
|
||||
scope.refresh();
|
||||
}
|
||||
scope.$emit('HostReloadComplete');
|
||||
}
|
||||
});
|
||||
|
||||
if (scope.removeInventorySubmit) {
|
||||
scope.removeInventorySubmit();
|
||||
}
|
||||
scope.removeInventorySubmit = scope.$on('InventorySubmit', function(e, passwords_needed_to_update, extra_html) {
|
||||
// After the call to update, kick off the job.
|
||||
PromptPasswords({
|
||||
scope: scope,
|
||||
passwords: passwords_needed_to_update,
|
||||
start_url: url,
|
||||
form: GroupForm,
|
||||
extra_html: extra_html
|
||||
});
|
||||
});
|
||||
|
||||
// Check to see if we have permission to perform the update and if any passwords are needed
|
||||
Wait('start');
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
if (data.can_update) {
|
||||
//var extra_html = "<div class=\"inventory-passwd-msg\">Starting inventory update for <em>" + group_name +
|
||||
// "</em>. Please provide the " + group_source + " credentials:</div>\n";
|
||||
scope.$emit('InventorySubmit', data.passwords_needed_to_update);
|
||||
}
|
||||
else {
|
||||
Wait('stop');
|
||||
Alert('Permission Denied', 'You do not have access to run the update. Please contact your system administrator.',
|
||||
'alert-danger');
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
scope.removeHostReloadComplete = scope.$on('HostReloadComplete', function () {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to get inventory_source details. ' + url + 'GET status: ' + status });
|
||||
Alert('Update Started', 'Your request to start the inventory sync process was submitted. Monitor progress ' +
|
||||
'by clicking the <i class="fa fa-refresh fa-lg"></i> button.', 'alert-info');
|
||||
if (scope.removeHostReloadComplete) {
|
||||
scope.removeHostReloadComplete();
|
||||
}
|
||||
});
|
||||
};
|
||||
}]);
|
||||
|
||||
if (scope.removeUpdateSubmitted) {
|
||||
scope.removeUpdateSubmitted();
|
||||
}
|
||||
scope.removeUpdateSubmitted = scope.$on('UpdateSubmitted', function (e, action) {
|
||||
if (action === 'started') {
|
||||
if (scope.refreshGroups) {
|
||||
scope.selected_tree_id = tree_id;
|
||||
scope.selected_group_id = group_id;
|
||||
scope.refreshGroups();
|
||||
} else if (scope.refresh) {
|
||||
scope.refresh();
|
||||
}
|
||||
scope.$emit('HostReloadComplete');
|
||||
}
|
||||
});
|
||||
|
||||
if (scope.removeInventorySubmit) {
|
||||
scope.removeInventorySubmit();
|
||||
}
|
||||
scope.removeInventorySubmit = scope.$on('InventorySubmit', function (e, passwords_needed_to_update, extra_html) {
|
||||
// After the call to update, kick off the job.
|
||||
PromptPasswords({
|
||||
scope: scope,
|
||||
passwords: passwords_needed_to_update,
|
||||
start_url: url,
|
||||
form: GroupForm,
|
||||
extra_html: extra_html
|
||||
});
|
||||
});
|
||||
|
||||
// Check to see if we have permission to perform the update and if any passwords are needed
|
||||
Wait('start');
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
if (data.can_update) {
|
||||
//var extra_html = "<div class=\"inventory-passwd-msg\">Starting inventory update for <em>" + group_name +
|
||||
// "</em>. Please provide the " + group_source + " credentials:</div>\n";
|
||||
scope.$emit('InventorySubmit', data.passwords_needed_to_update);
|
||||
} else {
|
||||
Wait('stop');
|
||||
Alert('Permission Denied', 'You do not have access to run the update. Please contact your system administrator.',
|
||||
'alert-danger');
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to get inventory_source details. ' + url + 'GET status: ' + status });
|
||||
});
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -4,15 +4,18 @@
|
||||
* JobsHelper
|
||||
*
|
||||
* Routines shared by job related controllers
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('JobsHelper', ['Utilities', 'FormGenerator', 'JobSummaryDefinition', 'InventoryHelper'])
|
||||
|
||||
.factory('JobStatusToolTip', [ function() {
|
||||
return function(status) {
|
||||
var toolTip;
|
||||
switch (status) {
|
||||
.factory('JobStatusToolTip', [
|
||||
function () {
|
||||
return function (status) {
|
||||
var toolTip;
|
||||
switch (status) {
|
||||
case 'successful':
|
||||
case 'success':
|
||||
toolTip = 'There were no failed tasks.';
|
||||
@ -35,118 +38,124 @@ angular.module('JobsHelper', ['Utilities', 'FormGenerator', 'JobSummaryDefinitio
|
||||
case 'running':
|
||||
toolTip = 'Playbook tasks executing.';
|
||||
break;
|
||||
}
|
||||
return toolTip;
|
||||
}
|
||||
return toolTip;
|
||||
};
|
||||
}])
|
||||
}
|
||||
])
|
||||
|
||||
.factory('ShowJobSummary', ['Rest', 'Wait', 'GetBasePath', 'FormatDate', 'ProcessErrors', 'GenerateForm', 'JobSummary',
|
||||
.factory('ShowJobSummary', ['Rest', 'Wait', 'GetBasePath', 'FormatDate', 'ProcessErrors', 'GenerateForm', 'JobSummary',
|
||||
'WatchInventoryWindowResize',
|
||||
function(Rest, Wait, GetBasePath, FormatDate, ProcessErrors, GenerateForm, JobSummary, WatchInventoryWindowResize) {
|
||||
return function(params) {
|
||||
// Display status info in a modal dialog- called from inventory edit page
|
||||
|
||||
var job_id = params.job_id;
|
||||
function (Rest, Wait, GetBasePath, FormatDate, ProcessErrors, GenerateForm, JobSummary, WatchInventoryWindowResize) {
|
||||
return function (params) {
|
||||
// Display status info in a modal dialog- called from inventory edit page
|
||||
|
||||
var generator = GenerateForm;
|
||||
var form = JobSummary;
|
||||
|
||||
// Using jquery dialog for its expandable property
|
||||
|
||||
var html = '<div id=\"status-modal-dialog\" title=\"Job ' + job_id + '\">' +
|
||||
'<div id=\"form-container\" style=\"width: 100%;\"></div></div>\n';
|
||||
|
||||
$('#inventory-modal-container').empty().append(html);
|
||||
var scope = generator.inject(form, { mode: 'edit', id: 'form-container', breadCrumbs: false, related: false });
|
||||
|
||||
// Set modal dimensions based on viewport width
|
||||
var ww = $(document).width();
|
||||
var wh = $('body').height();
|
||||
var x, y, maxrows;
|
||||
if (ww > 1199) {
|
||||
// desktop
|
||||
x = 675;
|
||||
y = (750 > wh) ? wh - 20 : 750;
|
||||
maxrows = 20;
|
||||
}
|
||||
else if (ww <= 1199 && ww >= 768) {
|
||||
x = 550;
|
||||
y = (620 > wh) ? wh - 15 : 620;
|
||||
maxrows = 15;
|
||||
}
|
||||
else {
|
||||
x = (ww - 20);
|
||||
y = (500 > wh) ? wh : 500;
|
||||
maxrows = 10;
|
||||
}
|
||||
|
||||
// Create the modal
|
||||
$('#status-modal-dialog').dialog({
|
||||
buttons: { 'OK': function() { $( this ).dialog( 'close' ); } },
|
||||
modal: true,
|
||||
width: x,
|
||||
height: y,
|
||||
autoOpen: false,
|
||||
create: function () {
|
||||
// fix the close button
|
||||
$('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-titlebar button')
|
||||
.empty().attr({ 'class': 'close' }).text('x');
|
||||
// fix the OK button
|
||||
$('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-buttonset button:first')
|
||||
.attr({ 'class': 'btn btn-primary' });
|
||||
},
|
||||
resizeStop: function() {
|
||||
// for some reason, after resizing dialog the form and fields (the content) doesn't expand to 100%
|
||||
var dialog = $('.ui-dialog[aria-describedby="status-modal-dialog"]');
|
||||
var content = dialog.find('#status-modal-dialog');
|
||||
content.width( dialog.width() - 28 );
|
||||
},
|
||||
close: function() {
|
||||
// Destroy on close
|
||||
$('.tooltip').each( function() {
|
||||
// Remove any lingering tooltip <div> elements
|
||||
$(this).remove();
|
||||
});
|
||||
$('.popover').each(function() {
|
||||
// remove lingering popover <div> elements
|
||||
$(this).remove();
|
||||
});
|
||||
$('#status-modal-dialog').dialog('destroy');
|
||||
$('#inventory-modal-container').empty();
|
||||
WatchInventoryWindowResize();
|
||||
},
|
||||
open: function() {
|
||||
Wait('stop');
|
||||
}
|
||||
});
|
||||
|
||||
function calcRows (content) {
|
||||
var n = content.match(/\n/g);
|
||||
var rows = (n) ? n.length : 1;
|
||||
return (rows > maxrows) ? 20 : rows;
|
||||
var job_id = params.job_id,
|
||||
generator = GenerateForm,
|
||||
form = JobSummary,
|
||||
scope, ww, wh, x, y, maxrows, url, html;
|
||||
|
||||
html = '<div id=\"status-modal-dialog\" title=\"Job ' + job_id + '\">' +
|
||||
'<div id=\"form-container\" style=\"width: 100%;\"></div></div>\n';
|
||||
|
||||
$('#inventory-modal-container').empty().append(html);
|
||||
|
||||
scope = generator.inject(form, { mode: 'edit', id: 'form-container', breadCrumbs: false, related: false });
|
||||
|
||||
// Set modal dimensions based on viewport width
|
||||
ww = $(document).width();
|
||||
wh = $('body').height();
|
||||
if (ww > 1199) {
|
||||
// desktop
|
||||
x = 675;
|
||||
y = (750 > wh) ? wh - 20 : 750;
|
||||
maxrows = 20;
|
||||
} else if (ww <= 1199 && ww >= 768) {
|
||||
x = 550;
|
||||
y = (620 > wh) ? wh - 15 : 620;
|
||||
maxrows = 15;
|
||||
} else {
|
||||
x = (ww - 20);
|
||||
y = (500 > wh) ? wh : 500;
|
||||
maxrows = 10;
|
||||
}
|
||||
|
||||
Wait('start');
|
||||
var url = GetBasePath('jobs') + job_id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success( function(data) {
|
||||
scope.id = data.id;
|
||||
scope.name = data.name;
|
||||
scope.status = data.status;
|
||||
scope.result_stdout = data.result_stdout;
|
||||
scope.result_traceback = data.result_traceback;
|
||||
scope.stdout_rows = calcRows(scope.result_stdout);
|
||||
scope.traceback_rows = calcRows(scope.result_traceback);
|
||||
var cDate = new Date(data.created);
|
||||
scope.created = FormatDate(cDate);
|
||||
$('#status-modal-dialog').dialog('open');
|
||||
// Create the modal
|
||||
$('#status-modal-dialog').dialog({
|
||||
buttons: {
|
||||
'OK': function () {
|
||||
$(this).dialog('close');
|
||||
}
|
||||
},
|
||||
modal: true,
|
||||
width: x,
|
||||
height: y,
|
||||
autoOpen: false,
|
||||
create: function () {
|
||||
// fix the close button
|
||||
$('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-titlebar button')
|
||||
.empty().attr({
|
||||
'class': 'close'
|
||||
}).text('x');
|
||||
// fix the OK button
|
||||
$('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-buttonset button:first')
|
||||
.attr({
|
||||
'class': 'btn btn-primary'
|
||||
});
|
||||
},
|
||||
resizeStop: function () {
|
||||
// for some reason, after resizing dialog the form and fields (the content) doesn't expand to 100%
|
||||
var dialog = $('.ui-dialog[aria-describedby="status-modal-dialog"]'),
|
||||
content = dialog.find('#status-modal-dialog');
|
||||
content.width(dialog.width() - 28);
|
||||
},
|
||||
close: function () {
|
||||
// Destroy on close
|
||||
$('.tooltip').each(function () {
|
||||
// Remove any lingering tooltip <div> elements
|
||||
$(this).remove();
|
||||
});
|
||||
$('.popover').each(function () {
|
||||
// remove lingering popover <div> elements
|
||||
$(this).remove();
|
||||
});
|
||||
$('#status-modal-dialog').dialog('destroy');
|
||||
$('#inventory-modal-container').empty();
|
||||
WatchInventoryWindowResize();
|
||||
},
|
||||
open: function () {
|
||||
Wait('stop');
|
||||
}
|
||||
});
|
||||
|
||||
function calcRows(content) {
|
||||
var n = content.match(/\n/g),
|
||||
rows = (n) ? n.length : 1;
|
||||
return (rows > maxrows) ? 20 : rows;
|
||||
}
|
||||
|
||||
Wait('start');
|
||||
url = GetBasePath('jobs') + job_id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
var cDate;
|
||||
scope.id = data.id;
|
||||
scope.name = data.name;
|
||||
scope.status = data.status;
|
||||
scope.result_stdout = data.result_stdout;
|
||||
scope.result_traceback = data.result_traceback;
|
||||
scope.stdout_rows = calcRows(scope.result_stdout);
|
||||
scope.traceback_rows = calcRows(scope.result_traceback);
|
||||
cDate = new Date(data.created);
|
||||
scope.created = FormatDate(cDate);
|
||||
$('#status-modal-dialog').dialog('open');
|
||||
})
|
||||
.error( function(data, status) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Attempt to load job failed. GET returned status: ' + status });
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Attempt to load job failed. GET returned status: ' + status });
|
||||
});
|
||||
};
|
||||
|
||||
}]);
|
||||
|
||||
}
|
||||
]);
|
||||
@ -3,7 +3,7 @@
|
||||
*
|
||||
* LookupHelper
|
||||
* Build a lookup dialog
|
||||
*
|
||||
*
|
||||
* LookUpInit( {
|
||||
* scope: <form scope>,
|
||||
* form: <form object>,
|
||||
@ -14,140 +14,150 @@
|
||||
* })
|
||||
*/
|
||||
|
||||
angular.module('LookUpHelper', [ 'RestServices', 'Utilities', 'SearchHelper', 'PaginationHelpers', 'ListGenerator', 'ApiLoader' ])
|
||||
'use strict';
|
||||
|
||||
angular.module('LookUpHelper', ['RestServices', 'Utilities', 'SearchHelper', 'PaginationHelpers', 'ListGenerator', 'ApiLoader'])
|
||||
.factory('LookUpInit', ['Alert', 'Rest', 'GenerateList', 'SearchInit', 'PaginateInit', 'GetBasePath', 'FormatDate', 'Empty',
|
||||
function(Alert, Rest, GenerateList, SearchInit, PaginateInit, GetBasePath, FormatDate, Empty) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope; // form scope
|
||||
var form = params.form; // form object
|
||||
var list = params.list; // list object
|
||||
var field = params.field; // form field
|
||||
var postAction = params.postAction //action to perform post user selection
|
||||
function (Alert, Rest, GenerateList, SearchInit, PaginateInit, GetBasePath, FormatDate, Empty) {
|
||||
return function (params) {
|
||||
|
||||
var defaultUrl;
|
||||
if (params.url) {
|
||||
// pass in a url value to override the default
|
||||
defaultUrl = params.url;
|
||||
}
|
||||
else {
|
||||
defaultUrl = (list.name == 'inventories') ? GetBasePath('inventory') : GetBasePath(list.name);
|
||||
}
|
||||
|
||||
// Show pop-up
|
||||
var name = list.iterator.charAt(0).toUpperCase() + list.iterator.substring(1);
|
||||
var hdr = (params.hdr) ? params.hdr : 'Select ' + name;
|
||||
var scope = params.scope,
|
||||
form = params.form,
|
||||
list = params.list,
|
||||
field = params.field,
|
||||
postAction = params.postAction,
|
||||
defaultUrl, name, hdr, watchUrl;
|
||||
|
||||
var watchUrl = (/\/$/.test(defaultUrl)) ? defaultUrl + '?' : defaultUrl + '&';
|
||||
watchUrl += form.fields[field].sourceField + '__' + 'iexact=:value';
|
||||
|
||||
$('input[name="' + form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '"]').attr('data-url', watchUrl);
|
||||
$('input[name="' + form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '"]').attr('data-source',field);
|
||||
|
||||
scope['lookUp' + name] = function() {
|
||||
var listGenerator = GenerateList;
|
||||
var listScope = listGenerator.inject(list, { mode: 'lookup', hdr: hdr });
|
||||
|
||||
$('#lookup-modal').on('hidden.bs.modal', function() {
|
||||
// If user clicks cancel without making a selection, make sure that field values are
|
||||
// in synch.
|
||||
if (listScope.searchCleanup) {
|
||||
listScope.searchCleanup();
|
||||
}
|
||||
if (scope[field] == '' || scope[field] == null) {
|
||||
scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField] = '';
|
||||
if (!scope.$$phase) {
|
||||
scope.$digest();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
listScope.selectAction = function() {
|
||||
var found = false;
|
||||
var name;
|
||||
for (var i=0; i < listScope[list.name].length; i++) {
|
||||
if (listScope[list.name][i]['checked'] == '1') {
|
||||
found = true;
|
||||
scope[field] = listScope[list.name][i].id;
|
||||
if (scope[form.name + '_form'] && form.fields[field] && form.fields[field].sourceModel) {
|
||||
scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField] =
|
||||
listScope[list.name][i][form.fields[field].sourceField];
|
||||
if (scope[form.name + '_form'][form.fields[field].sourceModel + '_' + form.fields[field].sourceField]) {
|
||||
scope[form.name + '_form'][form.fields[field].sourceModel + '_' + form.fields[field].sourceField]
|
||||
.$setValidity('awlookup',true);
|
||||
}
|
||||
}
|
||||
if (scope[form.name + '_form']) {
|
||||
scope[form.name + '_form'].$setDirty();
|
||||
}
|
||||
listGenerator.hide();
|
||||
}
|
||||
}
|
||||
if (found == false) {
|
||||
Alert('Missing Selection', 'Oops, you failed to make a selection. Click on a row to make your selection, ' +
|
||||
'and then click the Select button.');
|
||||
}
|
||||
else {
|
||||
if (postAction) {
|
||||
postAction();
|
||||
}
|
||||
}
|
||||
if (params.url) {
|
||||
// pass in a url value to override the default
|
||||
defaultUrl = params.url;
|
||||
} else {
|
||||
defaultUrl = (list.name === 'inventories') ? GetBasePath('inventory') : GetBasePath(list.name);
|
||||
}
|
||||
|
||||
listScope['toggle_' + list.iterator] = function(id) {
|
||||
for (var i=0; i < scope[list.name].length; i++) {
|
||||
if (listScope[list.name][i]['id'] == id) {
|
||||
listScope[list.name][i]['checked'] = '1';
|
||||
listScope[list.name][i]['success_class'] = 'success';
|
||||
}
|
||||
else {
|
||||
listScope[list.name][i]['checked'] = '0';
|
||||
listScope[list.name][i]['success_class'] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
SearchInit({ scope: listScope, set: list.name, list: list, url: defaultUrl });
|
||||
PaginateInit({ scope: listScope, list: list, url: defaultUrl, mode: 'lookup' });
|
||||
|
||||
// If user made a selection previously, mark it as selected when modal loads
|
||||
if (listScope.lookupPostRefreshRemove) {
|
||||
listScope.lookupPostRefreshRemove();
|
||||
}
|
||||
listScope.lookupPostRefreshRemove = scope.$on('PostRefresh', function() {
|
||||
for (var fld in list.fields) {
|
||||
if (list.fields[fld].type && list.fields[fld].type == 'date') {
|
||||
//convert dates to our standard format
|
||||
for (var i=0; i < scope[list.name].length; i++) {
|
||||
scope[list.name][i][fld] = FormatDate(new Date(scope[list.name][i][fld]));
|
||||
}
|
||||
}
|
||||
}
|
||||
// List generator creates the form, resetting it and losing the previously selected value.
|
||||
// Put it back based on the value of sourceModel_sourceName
|
||||
if (scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField] !== '' &&
|
||||
scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField] !== null) {
|
||||
for (var i=0; i < listScope[list.name].length; i++) {
|
||||
if (listScope[list.name][i][form.fields[field].sourceField] ==
|
||||
scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField]) {
|
||||
scope[field] = listScope[list.name][i].id;
|
||||
//scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField] =
|
||||
// listScope[list.name][i][form.fields[field].sourceField];
|
||||
break;
|
||||
// Show pop-up
|
||||
name = list.iterator.charAt(0).toUpperCase() + list.iterator.substring(1);
|
||||
hdr = (params.hdr) ? params.hdr : 'Select ' + name;
|
||||
|
||||
watchUrl = (/\/$/.test(defaultUrl)) ? defaultUrl + '?' : defaultUrl + '&';
|
||||
watchUrl += form.fields[field].sourceField + '__' + 'iexact=:value';
|
||||
|
||||
$('input[name="' + form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '"]').attr('data-url', watchUrl);
|
||||
$('input[name="' + form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '"]').attr('data-source', field);
|
||||
|
||||
scope['lookUp' + name] = function () {
|
||||
var listGenerator = GenerateList,
|
||||
listScope = listGenerator.inject(list, { mode: 'lookup', hdr: hdr });
|
||||
|
||||
$('#lookup-modal').on('hidden.bs.modal', function () {
|
||||
// If user clicks cancel without making a selection, make sure that field values are
|
||||
// in synch.
|
||||
if (listScope.searchCleanup) {
|
||||
listScope.searchCleanup();
|
||||
}
|
||||
if (scope[field] === '' || scope[field] === null) {
|
||||
scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField] = '';
|
||||
if (!scope.$$phase) {
|
||||
scope.$digest();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
listScope.selectAction = function () {
|
||||
var found = false, i;
|
||||
for (i = 0; i < listScope[list.name].length; i++) {
|
||||
if (listScope[list.name][i].checked === '1') {
|
||||
found = true;
|
||||
scope[field] = listScope[list.name][i].id;
|
||||
if (scope[form.name + '_form'] && form.fields[field] && form.fields[field].sourceModel) {
|
||||
scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField] =
|
||||
listScope[list.name][i][form.fields[field].sourceField];
|
||||
if (scope[form.name + '_form'][form.fields[field].sourceModel + '_' + form.fields[field].sourceField]) {
|
||||
scope[form.name + '_form'][form.fields[field].sourceModel + '_' + form.fields[field].sourceField]
|
||||
.$setValidity('awlookup', true);
|
||||
}
|
||||
}
|
||||
if (scope[form.name + '_form']) {
|
||||
scope[form.name + '_form'].$setDirty();
|
||||
}
|
||||
listGenerator.hide();
|
||||
}
|
||||
}
|
||||
if (found === false) {
|
||||
Alert('Missing Selection', 'Oops, you failed to make a selection. Click on a row to make your selection, ' +
|
||||
'and then click the Select button.');
|
||||
} else {
|
||||
if (postAction) {
|
||||
postAction();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
listScope['toggle_' + list.iterator] = function (id) {
|
||||
var i;
|
||||
for (i = 0; i < scope[list.name].length; i++) {
|
||||
if (listScope[list.name][i].id === id) {
|
||||
listScope[list.name][i].checked = '1';
|
||||
listScope[list.name][i].success_class = 'success';
|
||||
} else {
|
||||
listScope[list.name][i].checked = '0';
|
||||
listScope[list.name][i].success_class = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SearchInit({
|
||||
scope: listScope,
|
||||
set: list.name,
|
||||
list: list,
|
||||
url: defaultUrl
|
||||
});
|
||||
PaginateInit({
|
||||
scope: listScope,
|
||||
list: list,
|
||||
url: defaultUrl,
|
||||
mode: 'lookup'
|
||||
});
|
||||
|
||||
// If user made a selection previously, mark it as selected when modal loads
|
||||
if (listScope.lookupPostRefreshRemove) {
|
||||
listScope.lookupPostRefreshRemove();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!Empty(scope[field])) {
|
||||
listScope['toggle_' + list.iterator](scope[field]);
|
||||
}
|
||||
listScope.lookupPostRefreshRemove = scope.$on('PostRefresh', function () {
|
||||
var fld, i;
|
||||
for (fld in list.fields) {
|
||||
if (list.fields[fld].type && list.fields[fld].type === 'date') {
|
||||
//convert dates to our standard format
|
||||
for (i = 0; i < scope[list.name].length; i++) {
|
||||
scope[list.name][i][fld] = FormatDate(new Date(scope[list.name][i][fld]));
|
||||
}
|
||||
}
|
||||
}
|
||||
// List generator creates the form, resetting it and losing the previously selected value.
|
||||
// Put it back based on the value of sourceModel_sourceName
|
||||
if (scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField] !== '' &&
|
||||
scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField] !== null) {
|
||||
for (i = 0; i < listScope[list.name].length; i++) {
|
||||
if (listScope[list.name][i][form.fields[field].sourceField] ===
|
||||
scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField]) {
|
||||
scope[field] = listScope[list.name][i].id;
|
||||
//scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField] =
|
||||
// listScope[list.name][i][form.fields[field].sourceField];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
listScope.search(list.iterator);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!Empty(scope[field])) {
|
||||
listScope['toggle_' + list.iterator](scope[field]);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
listScope.search(list.iterator);
|
||||
|
||||
};
|
||||
};
|
||||
}
|
||||
}]);
|
||||
|
||||
|
||||
]);
|
||||
@ -5,165 +5,155 @@
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('PaginationHelpers', ['Utilities', 'RefreshHelper', 'RefreshRelatedHelper'])
|
||||
'use strict';
|
||||
|
||||
.factory('PageRangeSetup', ['Empty', function(Empty) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var count = params.count;
|
||||
var next = params.next;
|
||||
var previous = params.previous;
|
||||
var iterator = params.iterator;
|
||||
angular.module('PaginationHelpers', ['Utilities', 'RefreshHelper', 'RefreshRelatedHelper'])
|
||||
|
||||
scope[iterator + '_page'] = 1;
|
||||
scope[iterator + '_num_pages'] = Math.ceil((count / scope[iterator + '_page_size']));
|
||||
scope[iterator + '_num_pages'] = (scope[iterator + '_num_pages'] <= 0) ? 1 : scope[iterator + '_num_pages'];
|
||||
scope[iterator + '_total_rows'] = count;
|
||||
.factory('PageRangeSetup', ['Empty',
|
||||
function (Empty) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
count = params.count,
|
||||
next = params.next,
|
||||
previous = params.previous,
|
||||
iterator = params.iterator,
|
||||
i, first, last;
|
||||
|
||||
// Which page are we on?
|
||||
if ( Empty(next) && previous ) {
|
||||
// no next page, but there is a previous page
|
||||
scope[iterator + '_page'] = parseInt(previous.match(/page=\d+/)[0].replace(/page=/,'')) + 1;
|
||||
}
|
||||
else if ( next && Empty(previous) ) {
|
||||
// next page available, but no previous page
|
||||
scope[iterator + '_page'] = 1;
|
||||
}
|
||||
else if ( next && previous ) {
|
||||
// we're in between next and previous
|
||||
scope[iterator + '_page'] = parseInt(previous.match(/page=\d+/)[0].replace(/page=/,'')) + 1;
|
||||
}
|
||||
scope[iterator + '_num_pages'] = Math.ceil((count / scope[iterator + '_page_size']));
|
||||
scope[iterator + '_num_pages'] = (scope[iterator + '_num_pages'] <= 0) ? 1 : scope[iterator + '_num_pages'];
|
||||
scope[iterator + '_total_rows'] = count;
|
||||
|
||||
// Calc the range of up to 10 pages to show
|
||||
scope[iterator + '_page_range'] = new Array();
|
||||
var first = (scope[iterator + '_page'] > 5) ? scope[iterator + '_page'] - 5 : 1;
|
||||
if (scope[iterator + '_page'] < 6) {
|
||||
var last = (10 <= scope[iterator + '_num_pages']) ? 10 : scope[iterator + '_num_pages'];
|
||||
}
|
||||
else {
|
||||
var last = (scope[iterator + '_page'] + 4 < scope[iterator + '_num_pages']) ?
|
||||
scope[iterator + '_page'] + 4 : scope[iterator + '_num_pages'];
|
||||
}
|
||||
for (var i=first; i <= last; i++) {
|
||||
scope[iterator + '_page_range'].push(i);
|
||||
}
|
||||
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('RelatedPaginateInit', [ 'RefreshRelated', '$cookieStore', 'Wait',
|
||||
function(RefreshRelated, $cookieStore, Wait) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var relatedSets = params.relatedSets;
|
||||
var pageSize = (params.pageSize) ? params.pageSize : 10;
|
||||
|
||||
for (var key in relatedSets){
|
||||
cookieSize = $cookieStore.get(relatedSets[key].iterator + '_page_size');
|
||||
scope[relatedSets[key].iterator + '_url'] = relatedSets[key].url;
|
||||
if (cookieSize) {
|
||||
// use the size found in session cookie, when available
|
||||
scope[relatedSets[key].iterator + '_page_size'] = cookieSize;
|
||||
}
|
||||
else {
|
||||
scope[relatedSets[key].iterator + '_page'] = 0;
|
||||
scope[relatedSets[key].iterator + '_page_size'] = pageSize;
|
||||
}
|
||||
}
|
||||
|
||||
scope.getPage = function(page, set, iterator) {
|
||||
var new_url = scope[iterator + '_url'].replace(/.page\=\d+/,'');
|
||||
var connect = (/\/$/.test(new_url)) ? '?' : '&';
|
||||
new_url += connect + 'page=' + page;
|
||||
new_url += (scope[iterator + 'SearchParams']) ? '&' + scope[iterator + 'SearchParams'] +
|
||||
'&page_size=' + scope[iterator + '_page_size' ] : 'page_size=' + scope[iterator + 'PageSize' ];
|
||||
Wait('start');
|
||||
RefreshRelated({ scope: scope, set: set, iterator: iterator, url: new_url });
|
||||
// Which page are we on?
|
||||
if (Empty(next) && previous) {
|
||||
// no next page, but there is a previous page
|
||||
scope[iterator + '_page'] = parseInt(previous.match(/page=\d+/)[0].replace(/page=/, '')) + 1;
|
||||
} else if (next && Empty(previous)) {
|
||||
// next page available, but no previous page
|
||||
scope[iterator + '_page'] = 1;
|
||||
} else if (next && previous) {
|
||||
// we're in between next and previous
|
||||
scope[iterator + '_page'] = parseInt(previous.match(/page=\d+/)[0].replace(/page=/, '')) + 1;
|
||||
}
|
||||
|
||||
scope.pageIsActive = function(page, iterator) {
|
||||
return (page == scope[iterator + '_page']) ? 'active' : '';
|
||||
// Calc the range of up to 10 pages to show
|
||||
scope[iterator + '_page_range'] = [];
|
||||
first = (scope[iterator + '_page'] > 5) ? scope[iterator + '_page'] - 5 : 1;
|
||||
if (scope[iterator + '_page'] < 6) {
|
||||
last = (10 <= scope[iterator + '_num_pages']) ? 10 : scope[iterator + '_num_pages'];
|
||||
} else {
|
||||
last = (scope[iterator + '_page'] + 4 < scope[iterator + '_num_pages']) ?
|
||||
scope[iterator + '_page'] + 4 : scope[iterator + '_num_pages'];
|
||||
}
|
||||
for (i = first; i <= last; i++) {
|
||||
scope[iterator + '_page_range'].push(i);
|
||||
}
|
||||
|
||||
scope.changePageSize = function(set, iterator) {
|
||||
// Called when a new page size is selected
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
.factory('RelatedPaginateInit', ['RefreshRelated', '$cookieStore', 'Wait',
|
||||
function (RefreshRelated, $cookieStore, Wait) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
relatedSets = params.relatedSets,
|
||||
pageSize = (params.pageSize) ? params.pageSize : 10,
|
||||
key;
|
||||
|
||||
for (key in relatedSets) {
|
||||
scope[relatedSets[key].iterator + '_url'] = relatedSets[key].url;
|
||||
scope[relatedSets[key].iterator + '_page'] = 0;
|
||||
scope[relatedSets[key].iterator + '_page_size'] = pageSize;
|
||||
}
|
||||
|
||||
scope.getPage = function (page, set, iterator) {
|
||||
var new_url = scope[iterator + '_url'].replace(/.page\=\d+/, ''),
|
||||
connect = (/\/$/.test(new_url)) ? '?' : '&';
|
||||
new_url += connect + 'page=' + page;
|
||||
new_url += (scope[iterator + 'SearchParams']) ? '&' + scope[iterator + 'SearchParams'] +
|
||||
'&page_size=' + scope[iterator + '_page_size'] : 'page_size=' + scope[iterator + 'PageSize'];
|
||||
Wait('start');
|
||||
RefreshRelated({ scope: scope, set: set, iterator: iterator, url: new_url });
|
||||
};
|
||||
|
||||
scope.pageIsActive = function (page, iterator) {
|
||||
return (page === scope[iterator + '_page']) ? 'active' : '';
|
||||
};
|
||||
|
||||
scope.changePageSize = function (set, iterator) {
|
||||
// Called when a new page size is selected
|
||||
|
||||
scope[iterator + '_page'] = 1;
|
||||
var url = scope[iterator + '_url'];
|
||||
|
||||
// Using the session cookie, keep track of user rows per page selection
|
||||
$cookieStore.put(iterator + '_page_size', scope[iterator + '_page_size']);
|
||||
|
||||
url = url.replace(/\/\?.*$/, '/');
|
||||
url += (scope[iterator + 'SearchParams']) ? '?' + scope[iterator + 'SearchParams'] + '&page_size=' + scope[iterator + '_page_size'] :
|
||||
'?page_size=' + scope[iterator + '_page_size'];
|
||||
|
||||
RefreshRelated({
|
||||
scope: scope,
|
||||
set: set,
|
||||
iterator: iterator,
|
||||
url: url
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
.factory('PaginateInit', ['Refresh', '$cookieStore', 'Wait',
|
||||
function (Refresh, $cookieStore, Wait) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
list = params.list,
|
||||
iterator = (params.iterator) ? params.iterator : list.iterator,
|
||||
mode = (params.mode) ? params.mode : null;
|
||||
|
||||
scope[iterator + '_page'] = (params.page) ? params.page : 1;
|
||||
scope[iterator + '_url'] = params.url;
|
||||
scope[iterator + '_mode'] = mode;
|
||||
|
||||
if (params.pageSize) {
|
||||
scope[iterator + '_page_size'] = params.pageSize;
|
||||
} else if (mode === 'lookup') {
|
||||
scope[iterator + '_page_size'] = 5;
|
||||
} else {
|
||||
scope[iterator + '_page_size'] = 20;
|
||||
}
|
||||
|
||||
scope[iterator + '_page'] = 1;
|
||||
var url = scope[iterator + '_url'];
|
||||
scope.getPage = function (page, set, iterator) {
|
||||
var new_url = scope[iterator + '_url'].replace(/.page\=\d+/, ''),
|
||||
connect = (/\/$/.test(new_url)) ? '?' : '&';
|
||||
new_url += connect + 'page=' + page;
|
||||
new_url += (scope[iterator + 'SearchParams']) ? '&' + scope[iterator + 'SearchParams'] +
|
||||
'&page_size=' + scope[iterator + '_page_size'] : 'page_size=' + scope[iterator + 'PageSize'];
|
||||
Wait('start');
|
||||
Refresh({ scope: scope, set: set, iterator: iterator, url: new_url });
|
||||
};
|
||||
|
||||
// Using the session cookie, keep track of user rows per page selection
|
||||
$cookieStore.put(iterator + '_page_size', scope[iterator + '_page_size']);
|
||||
|
||||
url = url.replace(/\/\?.*$/,'/');
|
||||
url += (scope[iterator + 'SearchParams']) ? '?' + scope[iterator + 'SearchParams'] + '&page_size=' + scope[iterator + '_page_size' ] :
|
||||
'?page_size=' + scope[iterator + '_page_size' ];
|
||||
|
||||
RefreshRelated({ scope: scope, set: set, iterator: iterator, url: url });
|
||||
}
|
||||
scope.pageIsActive = function (page, iterator) {
|
||||
return (page === scope[iterator + '_page']) ? 'active' : '';
|
||||
};
|
||||
|
||||
}
|
||||
}])
|
||||
|
||||
|
||||
.factory('PaginateInit', [ 'Refresh', '$cookieStore', 'Wait',
|
||||
function(Refresh, $cookieStore, Wait) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var list = params.list;
|
||||
var iterator = (params.iterator) ? params.iterator : list.iterator;
|
||||
var mode = (params.mode) ? params.mode : null;
|
||||
var cookieSize = $cookieStore.get(iterator + '_page_size');
|
||||
|
||||
scope[iterator + '_page'] = (params.page) ? params.page : 1;
|
||||
scope[iterator + '_url'] = params.url;
|
||||
scope[iterator + '_mode'] = mode;
|
||||
|
||||
// Set the default page size
|
||||
if (cookieSize && mode != 'lookup') {
|
||||
// use the size found in session cookie, when available
|
||||
scope[iterator + '_page_size'] = cookieSize;
|
||||
}
|
||||
else {
|
||||
if (params.pageSize) {
|
||||
scope[iterator + '_page_size'] = params.pageSize;
|
||||
}
|
||||
else if (mode == 'lookup') {
|
||||
scope[iterator + '_page_size'] = 5;
|
||||
}
|
||||
else {
|
||||
scope[iterator + '_page_size'] = 20;
|
||||
}
|
||||
}
|
||||
|
||||
scope.getPage = function(page, set, iterator) {
|
||||
var new_url = scope[iterator + '_url'].replace(/.page\=\d+/,'');
|
||||
var connect = (/\/$/.test(new_url)) ? '?' : '&';
|
||||
new_url += connect + 'page=' + page;
|
||||
new_url += (scope[iterator + 'SearchParams']) ? '&' + scope[iterator + 'SearchParams'] +
|
||||
'&page_size=' + scope[iterator + '_page_size' ] : 'page_size=' + scope[iterator + 'PageSize' ];
|
||||
Wait('start');
|
||||
Refresh({ scope: scope, set: set, iterator: iterator, url: new_url });
|
||||
}
|
||||
|
||||
scope.pageIsActive = function(page, iterator) {
|
||||
return (page == scope[iterator + '_page']) ? 'active' : '';
|
||||
}
|
||||
|
||||
scope.changePageSize = function(set, iterator) {
|
||||
// Called whenever a new page size is selected
|
||||
// Using the session cookie, keep track of user rows per page selection
|
||||
$cookieStore.put(iterator + '_page_size', scope[iterator + '_page_size']);
|
||||
scope[iterator + '_page'] = 0;
|
||||
var new_url = scope[iterator + '_url'].replace(/\?page_size\=\d+/,'');
|
||||
var connect = (/\/$/.test(new_url)) ? '?' : '&';
|
||||
new_url += (scope[iterator + 'SearchParams']) ? connect + scope[iterator + 'SearchParams'] + '&page_size=' + scope[iterator + '_page_size' ] :
|
||||
connect + 'page_size=' + scope[iterator + '_page_size' ];
|
||||
Wait('start');
|
||||
Refresh({ scope: scope, set: set, iterator: iterator, url: new_url });
|
||||
}
|
||||
|
||||
}
|
||||
}]);
|
||||
scope.changePageSize = function (set, iterator) {
|
||||
// Called whenever a new page size is selected
|
||||
// Using the session cookie, keep track of user rows per page selection
|
||||
scope[iterator + '_page'] = 0;
|
||||
var new_url = scope[iterator + '_url'].replace(/\?page_size\=\d+/, ''),
|
||||
connect = (/\/$/.test(new_url)) ? '?' : '&';
|
||||
new_url += (scope[iterator + 'SearchParams']) ? connect + scope[iterator + 'SearchParams'] + '&page_size=' + scope[iterator + '_page_size'] :
|
||||
connect + 'page_size=' + scope[iterator + '_page_size'];
|
||||
Wait('start');
|
||||
Refresh({ scope: scope, set: set, iterator: iterator, url: new_url });
|
||||
};
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -3,61 +3,61 @@
|
||||
*
|
||||
* ParseHelper
|
||||
*
|
||||
* Routines for parsing variable data and toggling
|
||||
* Routines for parsing variable data and toggling
|
||||
* between JSON and YAML.
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('ParseHelper', [])
|
||||
.factory('ParseTypeChange', [function() {
|
||||
return function(scope, varName, parseTypeName) {
|
||||
'use strict';
|
||||
|
||||
// Toggle displayed variable string between JSON and YAML
|
||||
angular.module('ParseHelper', [])
|
||||
.factory('ParseTypeChange', [
|
||||
function () {
|
||||
return function (scope, varName, parseTypeName) {
|
||||
|
||||
var fld = (varName) ? varName : 'variables';
|
||||
var pfld = (parseTypeName) ? parseTypeName : 'parseType';
|
||||
|
||||
scope.blockParseTypeWatch = false;
|
||||
scope.blockVariableDataWatch = false;
|
||||
// Toggle displayed variable string between JSON and YAML
|
||||
|
||||
if (scope['remove' + fld + 'Watch']) {
|
||||
scope['remove' + fld + 'Watch']();
|
||||
var fld = (varName) ? varName : 'variables',
|
||||
pfld = (parseTypeName) ? parseTypeName : 'parseType';
|
||||
|
||||
scope.blockParseTypeWatch = false;
|
||||
scope.blockVariableDataWatch = false;
|
||||
|
||||
if (scope['remove' + fld + 'Watch']) {
|
||||
scope['remove' + fld + 'Watch']();
|
||||
}
|
||||
scope['remove' + fld + 'Watch'] = scope.$watch(pfld, function (newVal, oldVal) {
|
||||
var json_obj;
|
||||
if (newVal !== oldVal) {
|
||||
if (newVal === 'json') {
|
||||
if (scope[fld] && !/^---$/.test(scope[fld])) {
|
||||
// convert YAML to JSON
|
||||
try {
|
||||
json_obj = jsyaml.load(scope[fld]); //parse yaml into an obj
|
||||
scope[fld] = JSON.stringify(json_obj, null, " ");
|
||||
} catch (err) {
|
||||
// ignore parse errors. allow the user to paste values in and sync the
|
||||
// radio button later. parse errors will be flagged on save.
|
||||
}
|
||||
} else {
|
||||
scope[fld] = "{}";
|
||||
}
|
||||
} else {
|
||||
if (scope[fld] && !/^\{\}$/.test(scope[fld])) {
|
||||
// convert JSON to YAML
|
||||
try {
|
||||
json_obj = JSON.parse(scope[fld]);
|
||||
scope[fld] = jsyaml.safeDump(json_obj);
|
||||
} catch (err) {
|
||||
// ignore the errors. allow the user to paste values in and sync the
|
||||
// radio button later. parse errors will be flagged on save.
|
||||
}
|
||||
} else {
|
||||
scope[fld] = "---";
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
scope['remove' + fld + 'Watch'] = scope.$watch(pfld, function(newVal, oldVal) {
|
||||
if (newVal !== oldVal) {
|
||||
if (newVal == 'json') {
|
||||
if ( scope[fld] && !/^---$/.test(scope[fld])) {
|
||||
// convert YAML to JSON
|
||||
try {
|
||||
var json_obj = jsyaml.load(scope[fld]); //parse yaml into an obj
|
||||
scope[fld] = JSON.stringify(json_obj, null, " ");
|
||||
}
|
||||
catch (err) {
|
||||
// ignore parse errors. allow the user to paste values in and sync the
|
||||
// radio button later. parse errors will be flagged on save.
|
||||
}
|
||||
}
|
||||
else {
|
||||
scope[fld] = "\{\}";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( scope[fld] && !/^\{\}$/.test(scope[fld]) ) {
|
||||
// convert JSON to YAML
|
||||
try {
|
||||
var json_obj = JSON.parse(scope[fld]);
|
||||
scope[fld] = jsyaml.safeDump(json_obj);
|
||||
}
|
||||
catch (err) {
|
||||
// ignore the errors. allow the user to paste values in and sync the
|
||||
// radio button later. parse errors will be flagged on save.
|
||||
}
|
||||
}
|
||||
else {
|
||||
scope[fld] = "---";
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}]);
|
||||
]);
|
||||
@ -6,43 +6,42 @@
|
||||
* Functions shared amongst Permission related controllers
|
||||
*
|
||||
*/
|
||||
angular.module('PermissionsHelper', [])
|
||||
|
||||
// Handle category change event
|
||||
.factory('PermissionCategoryChange', [ function() {
|
||||
return function(params) {
|
||||
var scope = params.scope;
|
||||
var reset = params.reset;
|
||||
angular.module('PermissionsHelper', [])
|
||||
|
||||
if (scope.category == 'Inventory') {
|
||||
scope.projectrequired = false;
|
||||
scope.permissionTypeHelp =
|
||||
"<dl>\n" +
|
||||
"<dt>Read</dt>\n" +
|
||||
"<dd>Only allow the user or team to view the inventory.</dd>\n" +
|
||||
"<dt>Write</dt>\n" +
|
||||
"<dd>Allow the user or team to modify hosts and groups contained in the inventory, add new hosts and groups, and perform inventory sync operations.\n" +
|
||||
"<dt>Admin</dt>\n" +
|
||||
"<dd>Allow the user or team full access to the inventory. This includes reading, writing, deletion of the inventory and inventory sync operations.</dd>\n" +
|
||||
"</dl>\n";
|
||||
}
|
||||
else {
|
||||
scope.projectrequired = true;
|
||||
scope.permissionTypeHelp =
|
||||
"<dl>\n" +
|
||||
"<dt>Run</dt>\n" +
|
||||
"<dd>Allow the user or team to perform a live deployment of the project against the inventory. In Run mode modules will " +
|
||||
"be executed, and changes to the inventory will occur.</dd>\n" +
|
||||
"<dt>Check</dt>\n" +
|
||||
"<dd>Only allow the user or team to deploy the project against the inventory as a dry-run operation. In Check mode, module operations " +
|
||||
"will only be simulated. No changes will occur.</dd>\n" +
|
||||
"</dl>\n";
|
||||
}
|
||||
// Handle category change event
|
||||
.factory('PermissionCategoryChange', [
|
||||
function () {
|
||||
return function (params) {
|
||||
var scope = params.scope,
|
||||
reset = params.reset;
|
||||
|
||||
if (reset) {
|
||||
scope.permission_type = (scope.category == 'Inventory') ? 'read' : 'run'; //default to the first option
|
||||
}
|
||||
|
||||
}
|
||||
}]);
|
||||
|
||||
if (scope.category === 'Inventory') {
|
||||
scope.projectrequired = false;
|
||||
scope.permissionTypeHelp =
|
||||
"<dl>\n" +
|
||||
"<dt>Read</dt>\n" +
|
||||
"<dd>Only allow the user or team to view the inventory.</dd>\n" +
|
||||
"<dt>Write</dt>\n" +
|
||||
"<dd>Allow the user or team to modify hosts and groups contained in the inventory, add new hosts and groups, and perform inventory sync operations.\n" +
|
||||
"<dt>Admin</dt>\n" +
|
||||
"<dd>Allow the user or team full access to the inventory. This includes reading, writing, deletion of the inventory and inventory sync operations.</dd>\n" +
|
||||
"</dl>\n";
|
||||
} else {
|
||||
scope.projectrequired = true;
|
||||
scope.permissionTypeHelp =
|
||||
"<dl>\n" +
|
||||
"<dt>Run</dt>\n" +
|
||||
"<dd>Allow the user or team to perform a live deployment of the project against the inventory. In Run mode modules will " +
|
||||
"be executed, and changes to the inventory will occur.</dd>\n" +
|
||||
"<dt>Check</dt>\n" +
|
||||
"<dd>Only allow the user or team to deploy the project against the inventory as a dry-run operation. In Check mode, module operations " +
|
||||
"will only be simulated. No changes will occur.</dd>\n" +
|
||||
"</dl>\n";
|
||||
}
|
||||
|
||||
if (reset) {
|
||||
scope.permission_type = (scope.category === 'Inventory') ? 'read' : 'run'; //default to the first option
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -3,73 +3,79 @@
|
||||
*
|
||||
* ProjectPathHelper
|
||||
*
|
||||
* Use GetProjectPath({ scope: <scope>, master: <master obj> }) to
|
||||
* Use GetProjectPath({ scope: <scope>, master: <master obj> }) to
|
||||
* load scope.project_local_paths (array of options for drop-down) and
|
||||
* scope.base_dir (readonly field).
|
||||
* scope.base_dir (readonly field).
|
||||
*
|
||||
*/
|
||||
angular.module('ProjectPathHelper', ['RestServices', 'Utilities'])
|
||||
.factory('GetProjectPath', ['Alert', 'Rest', 'GetBasePath', 'ProcessErrors',
|
||||
function (Alert, Rest, GetBasePath, ProcessErrors) {
|
||||
return function (params) {
|
||||
|
||||
angular.module('ProjectPathHelper', ['RestServices', 'Utilities'])
|
||||
.factory('GetProjectPath', ['Alert', 'Rest', 'GetBasePath','ProcessErrors',
|
||||
function(Alert, Rest, GetBasePath, ProcessErrors) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var master = params.master;
|
||||
|
||||
function arraySort(data) {
|
||||
//Sort nodes by name
|
||||
var names = [];
|
||||
var newData = [];
|
||||
for (var i=0; i < data.length; i++) {
|
||||
names.push(data[i].value);
|
||||
}
|
||||
names.sort();
|
||||
for (var j=0; j < names.length; j++) {
|
||||
for (i=0; i < data.length; i++) {
|
||||
if (data[i].value == names[j]) {
|
||||
newData.push(data[i]);
|
||||
var scope = params.scope,
|
||||
master = params.master;
|
||||
|
||||
function arraySort(data) {
|
||||
//Sort nodes by name
|
||||
var i, j, names = [],
|
||||
newData = [];
|
||||
for (i = 0; i < data.length; i++) {
|
||||
names.push(data[i].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newData;
|
||||
}
|
||||
|
||||
scope.showMissingPlaybooksAlert = false;
|
||||
|
||||
Rest.setUrl( GetBasePath('config') );
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
var opts = [];
|
||||
for (var i=0; i < data.project_local_paths.length; i++) {
|
||||
opts.push({ label: data.project_local_paths[i], value: data.project_local_paths[i] });
|
||||
}
|
||||
if (scope.local_path) {
|
||||
// List only includes paths not assigned to projects, so add the
|
||||
// path assigned to the current project.
|
||||
opts.push({ label: scope.local_path, value: scope.local_path });
|
||||
}
|
||||
scope.project_local_paths = arraySort(opts);
|
||||
if (scope.local_path) {
|
||||
for (var i=0; scope.project_local_paths.length; i++) {
|
||||
if (scope.project_local_paths[i].value == scope.local_path) {
|
||||
scope.local_path = scope.project_local_paths[i];
|
||||
break;
|
||||
}
|
||||
names.sort();
|
||||
for (j = 0; j < names.length; j++) {
|
||||
for (i = 0; i < data.length; i++) {
|
||||
if (data[i].value === names[j]) {
|
||||
newData.push(data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newData;
|
||||
}
|
||||
scope.base_dir = data.project_base_dir;
|
||||
master.local_path = scope.local_path;
|
||||
master.base_dir = scope.base_dir; // Keep in master object so that it doesn't get
|
||||
// wiped out on form reset.
|
||||
if (opts.length == 0) {
|
||||
// trigger display of alert block when scm_type == manual
|
||||
scope.showMissingPlaybooksAlert = true;
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to access API config. GET status: ' + status });
|
||||
});
|
||||
|
||||
scope.showMissingPlaybooksAlert = false;
|
||||
|
||||
Rest.setUrl(GetBasePath('config'));
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
var opts = [], i;
|
||||
for (i = 0; i < data.project_local_paths.length; i++) {
|
||||
opts.push({
|
||||
label: data.project_local_paths[i],
|
||||
value: data.project_local_paths[i]
|
||||
});
|
||||
}
|
||||
if (scope.local_path) {
|
||||
// List only includes paths not assigned to projects, so add the
|
||||
// path assigned to the current project.
|
||||
opts.push({
|
||||
label: scope.local_path,
|
||||
value: scope.local_path
|
||||
});
|
||||
}
|
||||
scope.project_local_paths = arraySort(opts);
|
||||
if (scope.local_path) {
|
||||
for (i = 0; scope.project_local_paths.length; i++) {
|
||||
if (scope.project_local_paths[i].value === scope.local_path) {
|
||||
scope.local_path = scope.project_local_paths[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
scope.base_dir = data.project_base_dir;
|
||||
master.local_path = scope.local_path;
|
||||
master.base_dir = scope.base_dir; // Keep in master object so that it doesn't get
|
||||
// wiped out on form reset.
|
||||
if (opts.length === 0) {
|
||||
// trigger display of alert block when scm_type == manual
|
||||
scope.showMissingPlaybooksAlert = true;
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to access API config. GET status: ' + status });
|
||||
});
|
||||
};
|
||||
}
|
||||
}]);
|
||||
]);
|
||||
@ -3,125 +3,133 @@
|
||||
*
|
||||
* ProjectsHelper
|
||||
*
|
||||
* Use GetProjectPath({ scope: <scope>, master: <master obj> }) to
|
||||
* Use GetProjectPath({ scope: <scope>, master: <master obj> }) to
|
||||
* load scope.project_local_paths (array of options for drop-down) and
|
||||
* scope.base_dir (readonly field).
|
||||
* scope.base_dir (readonly field).
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('ProjectsHelper', ['RestServices', 'Utilities', 'ProjectStatusDefinition', 'ProjectFormDefinition'])
|
||||
|
||||
.factory('ProjectStatus', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GenerateForm',
|
||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'FormatDate', 'ProjectStatusForm', 'Wait',
|
||||
function($rootScope, $location, $log, $routeParams, Rest, Alert, GenerateForm, Prompt, ProcessErrors, GetBasePath,
|
||||
FormatDate, ProjectStatusForm, Wait) {
|
||||
return function(params) {
|
||||
.factory('ProjectStatus', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GenerateForm',
|
||||
'Prompt', 'ProcessErrors', 'GetBasePath', 'FormatDate', 'ProjectStatusForm', 'Wait',
|
||||
function ($rootScope, $location, $log, $routeParams, Rest, Alert, GenerateForm, Prompt, ProcessErrors, GetBasePath,
|
||||
FormatDate, ProjectStatusForm, Wait) {
|
||||
return function (params) {
|
||||
|
||||
var project_id = params.project_id;
|
||||
var last_update = params.last_update;
|
||||
|
||||
var generator = GenerateForm;
|
||||
var form = ProjectStatusForm;
|
||||
|
||||
Wait('start');
|
||||
var project_id = params.project_id,
|
||||
last_update = params.last_update,
|
||||
generator = GenerateForm,
|
||||
form = ProjectStatusForm,
|
||||
html, scope, ww, wh, x, y, maxrows;
|
||||
|
||||
// Using jquery dialog for its expandable property
|
||||
var html = "<div id=\"status-modal-dialog\"><div id=\"form-container\" style=\"width: 100%;\"></div></div>\n";
|
||||
$('#projects-modal-container').empty().append(html);
|
||||
Wait('start');
|
||||
|
||||
var scope = generator.inject(form, { mode: 'edit', id: 'form-container', related: false, breadCrumbs: false });
|
||||
generator.reset();
|
||||
// Using jquery dialog for its expandable property
|
||||
html = "<div id=\"status-modal-dialog\"><div id=\"form-container\" style=\"width: 100%;\"></div></div>\n";
|
||||
$('#projects-modal-container').empty().append(html);
|
||||
|
||||
// Set modal dimensions based on viewport width
|
||||
var ww = $(document).width();
|
||||
var wh = $('body').height();
|
||||
var x, y, maxrows;
|
||||
if (ww > 1199) {
|
||||
// desktop
|
||||
x = 675;
|
||||
y = (750 > wh) ? wh - 20 : 750;
|
||||
maxrows = 20;
|
||||
}
|
||||
else if (ww <= 1199 && ww >= 768) {
|
||||
x = 550;
|
||||
y = (620 > wh) ? wh - 15 : 620;
|
||||
maxrows = 15;
|
||||
}
|
||||
else {
|
||||
x = (ww - 20);
|
||||
y = (500 > wh) ? wh : 500;
|
||||
maxrows = 10;
|
||||
}
|
||||
// Create the modal
|
||||
$('#status-modal-dialog').dialog({
|
||||
buttons: { "OK": function() { $( this ).dialog( "close" ); } },
|
||||
modal: true,
|
||||
width: x,
|
||||
height: y,
|
||||
autoOpen: false,
|
||||
create: function (e, ui) {
|
||||
// fix the close button
|
||||
$('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-titlebar button').empty().attr({ 'class': 'close' }).text('x');
|
||||
// fix the OK button
|
||||
$('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-buttonset button:first')
|
||||
.attr({ 'class': 'btn btn-primary' });
|
||||
scope = generator.inject(form, { mode: 'edit', id: 'form-container', related: false, breadCrumbs: false });
|
||||
generator.reset();
|
||||
|
||||
// Set modal dimensions based on viewport width
|
||||
ww = $(document).width();
|
||||
wh = $('body').height();
|
||||
if (ww > 1199) {
|
||||
// desktop
|
||||
x = 675;
|
||||
y = (750 > wh) ? wh - 20 : 750;
|
||||
maxrows = 20;
|
||||
} else if (ww <= 1199 && ww >= 768) {
|
||||
x = 550;
|
||||
y = (620 > wh) ? wh - 15 : 620;
|
||||
maxrows = 15;
|
||||
} else {
|
||||
x = (ww - 20);
|
||||
y = (500 > wh) ? wh : 500;
|
||||
maxrows = 10;
|
||||
}
|
||||
// Create the modal
|
||||
$('#status-modal-dialog').dialog({
|
||||
buttons: {
|
||||
"OK": function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
},
|
||||
resizeStop: function(e, ui) {
|
||||
// for some reason, after resizing dialog the form and fields (the content) doesn't expand to 100%
|
||||
var dialog = $('.ui-dialog[aria-describedby="status-modal-dialog"]');
|
||||
var content = dialog.find('#status-modal-dialog');
|
||||
content.width( dialog.width() - 28 );
|
||||
modal: true,
|
||||
width: x,
|
||||
height: y,
|
||||
autoOpen: false,
|
||||
create: function () {
|
||||
// fix the close button
|
||||
$('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-titlebar button').empty().attr({
|
||||
'class': 'close'
|
||||
}).text('x');
|
||||
// fix the OK button
|
||||
$('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-buttonset button:first')
|
||||
.attr({
|
||||
'class': 'btn btn-primary'
|
||||
});
|
||||
},
|
||||
close: function(e, ui) {
|
||||
// Destroy on close
|
||||
// Destroy on close
|
||||
$('.tooltip').each( function(index) {
|
||||
// Remove any lingering tooltip <div> elements
|
||||
$(this).remove();
|
||||
resizeStop: function () {
|
||||
// for some reason, after resizing dialog the form and fields (the content) doesn't expand to 100%
|
||||
var dialog = $('.ui-dialog[aria-describedby="status-modal-dialog"]'),
|
||||
content = dialog.find('#status-modal-dialog');
|
||||
content.width(dialog.width() - 28);
|
||||
},
|
||||
close: function () {
|
||||
// Destroy on close
|
||||
// Destroy on close
|
||||
$('.tooltip').each(function () {
|
||||
// Remove any lingering tooltip <div> elements
|
||||
$(this).remove();
|
||||
});
|
||||
$('.popover').each(function(index) {
|
||||
// remove lingering popover <div> elements
|
||||
$(this).remove();
|
||||
$('.popover').each(function () {
|
||||
// remove lingering popover <div> elements
|
||||
$(this).remove();
|
||||
});
|
||||
$('#status-modal-dialog').dialog('destroy');
|
||||
$('#projects-modal-container').empty();
|
||||
$('#status-modal-dialog').dialog('destroy');
|
||||
$('#projects-modal-container').empty();
|
||||
},
|
||||
open: function(e, ui) {
|
||||
Wait('stop');
|
||||
open: function () {
|
||||
Wait('stop');
|
||||
}
|
||||
});
|
||||
|
||||
// Retrieve detail record and prepopulate the form
|
||||
Rest.setUrl(last_update);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
var results = data;
|
||||
for (var fld in form.fields) {
|
||||
if (results[fld]) {
|
||||
if (fld == 'created') {
|
||||
scope[fld] = FormatDate(new Date(results[fld]));
|
||||
}
|
||||
else {
|
||||
scope[fld] = results[fld];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (results.summary_fields.project[fld]) {
|
||||
scope[fld] = results.summary_fields.project[fld]
|
||||
}
|
||||
}
|
||||
}
|
||||
$('#status-modal-dialog')
|
||||
.dialog({ title: results.summary_fields.project.name + ' Status'})
|
||||
.dialog('open');
|
||||
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
$('#form-modal').modal("hide");
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to retrieve status of project: ' + project_id + '. GET status: ' + status });
|
||||
});
|
||||
}
|
||||
}]);
|
||||
|
||||
|
||||
// Retrieve detail record and prepopulate the form
|
||||
Rest.setUrl(last_update);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
var results = data, fld;
|
||||
for (fld in form.fields) {
|
||||
if (results[fld]) {
|
||||
if (fld === 'created') {
|
||||
scope[fld] = FormatDate(new Date(results[fld]));
|
||||
} else {
|
||||
scope[fld] = results[fld];
|
||||
}
|
||||
} else {
|
||||
if (results.summary_fields.project[fld]) {
|
||||
scope[fld] = results.summary_fields.project[fld];
|
||||
}
|
||||
}
|
||||
}
|
||||
$('#status-modal-dialog')
|
||||
.dialog({
|
||||
title: results.summary_fields.project.name + ' Status'
|
||||
})
|
||||
.dialog('open');
|
||||
|
||||
})
|
||||
.error(function (data, status) {
|
||||
$('#form-modal').modal("hide");
|
||||
ProcessErrors(scope, data, status, form, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to retrieve status of project: ' + project_id + '. GET status: ' + status
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -3,167 +3,172 @@
|
||||
*
|
||||
* SelectionHelper
|
||||
* Used in list controllers where the list might also be used as a selection list.
|
||||
*
|
||||
*
|
||||
* SelectionInit( {
|
||||
* scope: <list scope>,
|
||||
* list: <list object>
|
||||
* })
|
||||
*/
|
||||
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('SelectionHelper', ['Utilities', 'RestServices'])
|
||||
|
||||
.factory('SelectionInit', [ 'Rest', 'Alert', 'ProcessErrors', 'ReturnToCaller', 'Wait',
|
||||
function(Rest, Alert, ProcessErrors, ReturnToCaller, Wait) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope; // current scope
|
||||
var list = params.list; // list object
|
||||
var target_url = params.url; // URL to POST selected objects
|
||||
var returnToCaller = params.returnToCaller;
|
||||
.factory('SelectionInit', ['Rest', 'Alert', 'ProcessErrors', 'ReturnToCaller', 'Wait',
|
||||
function (Rest, Alert, ProcessErrors, ReturnToCaller, Wait) {
|
||||
return function (params) {
|
||||
|
||||
if (params.selected !== undefined) {
|
||||
var selected = params.selected;
|
||||
}
|
||||
else {
|
||||
var selected = []; //array of selected row IDs
|
||||
}
|
||||
var scope = params.scope,
|
||||
list = params.list,
|
||||
target_url = params.url,
|
||||
returnToCaller = params.returnToCaller,
|
||||
selected;
|
||||
|
||||
scope.formModalActionDisabled = true;
|
||||
scope.disableSelectBtn = true;
|
||||
if (params.selected !== undefined) {
|
||||
selected = params.selected;
|
||||
} else {
|
||||
selected = []; //array of selected row IDs
|
||||
}
|
||||
|
||||
// toggle row selection
|
||||
scope['toggle_' + list.iterator] = function(id, ischeckbox) {
|
||||
for (var i=0; i < scope[list.name].length; i++) {
|
||||
if (scope[list.name][i]['id'] == id) {
|
||||
if ( (scope[list.name][i]['checked'] == '0' && !ischeckbox) || (scope[list.name][i]['checked'] == 1 && ischeckbox) ) {
|
||||
// select the row
|
||||
scope[list.name][i]['checked'] = '1';
|
||||
scope[list.name][i]['success_class'] = 'success';
|
||||
|
||||
// add selected object to the array
|
||||
var found = false;
|
||||
for (var j=0; j < selected.length; j++) {
|
||||
if (selected[j].id == id) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
selected.push(scope[list.name][i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// unselect the row
|
||||
scope[list.name][i]['checked'] = '0';
|
||||
scope[list.name][i]['success_class'] = '';
|
||||
|
||||
// remove selected object from the array
|
||||
for (var j=0; j < selected.length; j++) {
|
||||
if (selected[j].id == id) {
|
||||
selected.splice(j,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selected.length > 0) {
|
||||
scope.formModalActionDisabled = false;
|
||||
scope.disableSelectBtn = false;
|
||||
}
|
||||
else {
|
||||
scope.formModalActionDisabled = true;
|
||||
scope.disableSelectBtn = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the selections
|
||||
scope.finishSelection = function() {
|
||||
Rest.setUrl(target_url);
|
||||
var queue = [];
|
||||
scope.formModalActionDisabled = true;
|
||||
scope.disableSelectBtn = true;
|
||||
|
||||
Wait('start');
|
||||
|
||||
function finished() {
|
||||
selected = [];
|
||||
if (returnToCaller !== undefined) {
|
||||
ReturnToCaller(returnToCaller);
|
||||
// toggle row selection
|
||||
scope['toggle_' + list.iterator] = function (id, ischeckbox) {
|
||||
var i, j, found;
|
||||
for (i = 0; i < scope[list.name].length; i++) {
|
||||
if (scope[list.name][i].id === id) {
|
||||
if ((scope[list.name][i].checked === '0' && !ischeckbox) || (scope[list.name][i].checked === 1 && ischeckbox)) {
|
||||
// select the row
|
||||
scope[list.name][i].checked = '1';
|
||||
scope[list.name][i].success_class = 'success';
|
||||
|
||||
// add selected object to the array
|
||||
found = false;
|
||||
for (j = 0; j < selected.length; j++) {
|
||||
if (selected[j].id === id) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
selected.push(scope[list.name][i]);
|
||||
}
|
||||
} else {
|
||||
// unselect the row
|
||||
scope[list.name][i].checked = '0';
|
||||
scope[list.name][i].success_class = '';
|
||||
|
||||
// remove selected object from the array
|
||||
for (j = 0; j < selected.length; j++) {
|
||||
if (selected[j].id === id) {
|
||||
selected.splice(j, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$('#form-modal').modal('hide');
|
||||
scope.$emit('modalClosed');
|
||||
if (selected.length > 0) {
|
||||
scope.formModalActionDisabled = false;
|
||||
scope.disableSelectBtn = false;
|
||||
} else {
|
||||
scope.formModalActionDisabled = true;
|
||||
scope.disableSelectBtn = true;
|
||||
}
|
||||
};
|
||||
|
||||
// Add the selections
|
||||
scope.finishSelection = function () {
|
||||
Rest.setUrl(target_url);
|
||||
|
||||
var queue = [], j;
|
||||
|
||||
scope.formModalActionDisabled = true;
|
||||
scope.disableSelectBtn = true;
|
||||
|
||||
Wait('start');
|
||||
|
||||
function finished() {
|
||||
selected = [];
|
||||
if (returnToCaller !== undefined) {
|
||||
ReturnToCaller(returnToCaller);
|
||||
} else {
|
||||
$('#form-modal').modal('hide');
|
||||
scope.$emit('modalClosed');
|
||||
}
|
||||
}
|
||||
|
||||
if (scope.callFinishedRemove) {
|
||||
scope.callFinishedRemove();
|
||||
}
|
||||
scope.callFinishedRemove = scope.$on('callFinished', function() {
|
||||
// We call the API for each selected item. We need to hang out until all the api
|
||||
// calls are finished.
|
||||
if (queue.length == selected.length) {
|
||||
Wait('stop');
|
||||
var errors = 0;
|
||||
for (var i=0; i < queue.length; i++) {
|
||||
if (queue[i].result == 'error') {
|
||||
ProcessErrors(scope, queue[i].data, queue[i].status, null,
|
||||
{ hdr: 'POST Failure', msg: 'Failed to add ' + list.iterator +
|
||||
'. POST returned status: ' + queue[i].status });
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if (errors == 0) {
|
||||
finished();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (selected.length > 0 ) {
|
||||
for (var j=0; j < selected.length; j++) {
|
||||
Rest.post(selected[j])
|
||||
.success( function(data, status, headers, config) {
|
||||
queue.push({ result: 'success', data: data, status: status });
|
||||
scope.$emit('callFinished');
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
queue.push({ result: 'error', data: data, status: status, headers: headers });
|
||||
scope.$emit('callFinished');
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
finished();
|
||||
}
|
||||
}
|
||||
function postIt(data) {
|
||||
Rest.post(data)
|
||||
.success(function (data, status) {
|
||||
queue.push({ result: 'success', data: data, status: status });
|
||||
scope.$emit('callFinished');
|
||||
})
|
||||
.error(function (data, status, headers) {
|
||||
queue.push({ result: 'error', data: data, status: status, headers: headers });
|
||||
scope.$emit('callFinished');
|
||||
});
|
||||
}
|
||||
|
||||
scope.formModalAction = scope.finishSelection;
|
||||
if (scope.callFinishedRemove) {
|
||||
scope.callFinishedRemove();
|
||||
}
|
||||
scope.callFinishedRemove = scope.$on('callFinished', function () {
|
||||
// We call the API for each selected item. We need to hang out until all the api
|
||||
// calls are finished.
|
||||
var i, errors=0;
|
||||
if (queue.length === selected.length) {
|
||||
Wait('stop');
|
||||
for (i = 0; i < queue.length; i++) {
|
||||
if (queue[i].result === 'error') {
|
||||
ProcessErrors(scope, queue[i].data, queue[i].status, null, { hdr: 'POST Failure',
|
||||
msg: 'Failed to add ' + list.iterator + '. POST returned status: ' + queue[i].status });
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if (errors === 0) {
|
||||
finished();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize our data set after a refresh (page change or search)
|
||||
if (scope.SelectPostRefreshRemove) {
|
||||
scope.SelectPostRefreshRemove();
|
||||
}
|
||||
scope.SelectPostRefreshRemove = scope.$on('PostRefresh', function() {
|
||||
if (scope[list.name]) {
|
||||
for (var i=0; i < scope[list.name].length; i++) {
|
||||
var found = false;
|
||||
for (var j=0; j < selected.length; j++) {
|
||||
if (selected[j].id == scope[list.name][i].id) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
scope[list.name][i]['checked'] = '1';
|
||||
scope[list.name][i]['success_class'] = 'success';
|
||||
}
|
||||
else {
|
||||
scope[list.name][i]['checked'] = '0';
|
||||
scope[list.name][i]['success_class'] = '';
|
||||
}
|
||||
}
|
||||
if (selected.length > 0) {
|
||||
for (j = 0; j < selected.length; j++) {
|
||||
postIt(selected[j]);
|
||||
}
|
||||
} else {
|
||||
finished();
|
||||
}
|
||||
};
|
||||
|
||||
scope.formModalAction = scope.finishSelection;
|
||||
|
||||
// Initialize our data set after a refresh (page change or search)
|
||||
if (scope.SelectPostRefreshRemove) {
|
||||
scope.SelectPostRefreshRemove();
|
||||
}
|
||||
scope.SelectPostRefreshRemove = scope.$on('PostRefresh', function () {
|
||||
var i, j, found;
|
||||
if (scope[list.name]) {
|
||||
for (i = 0; i < scope[list.name].length; i++) {
|
||||
found = false;
|
||||
for (j = 0; j < selected.length; j++) {
|
||||
if (selected[j].id === scope[list.name][i].id) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
scope[list.name][i].checked = '1';
|
||||
scope[list.name][i].success_class = 'success';
|
||||
} else {
|
||||
scope[list.name][i].checked = '0';
|
||||
scope[list.name][i].success_class = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}]);
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -2,27 +2,38 @@
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* UserHelper
|
||||
* Routines shared amongst the user controllers
|
||||
* Routines shared amongst the user controllers
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('UserHelper', [ 'UserFormDefinition' ])
|
||||
.factory('ResetForm', ['UserForm', function(UserForm) {
|
||||
return function() {
|
||||
// Restore form to default conditions. Run before applying LDAP configuration.
|
||||
// LDAP may manage some or all of these fields in which case the user cannot
|
||||
// make changes to their values in AWX.
|
||||
|
||||
UserForm.fields['first_name'].readonly = false;
|
||||
UserForm.fields['first_name'].editRequired = true;
|
||||
UserForm.fields['last_name'].readonly = false;
|
||||
UserForm.fields['last_name'].editRequired = true;
|
||||
UserForm.fields['email'].readonly = false;
|
||||
UserForm.fields['email'].editRequired = true;
|
||||
UserForm.fields['organization'].awRequiredWhen = { variable: "orgrequired", init: true};
|
||||
UserForm.fields['organization'].readonly = false;
|
||||
UserForm.fields['username'].awRequiredWhen = { variable: "not_ldap_user", init: true };
|
||||
UserForm.fields['username'].readonly = false;
|
||||
UserForm.fields['password'].editRequired = false;
|
||||
UserForm.fields['password'].addRrequired = true;
|
||||
}
|
||||
}]);
|
||||
'use strict';
|
||||
|
||||
angular.module('UserHelper', ['UserFormDefinition'])
|
||||
.factory('ResetForm', ['UserForm',
|
||||
function (UserForm) {
|
||||
return function () {
|
||||
// Restore form to default conditions. Run before applying LDAP configuration.
|
||||
// LDAP may manage some or all of these fields in which case the user cannot
|
||||
// make changes to their values in AWX.
|
||||
|
||||
UserForm.fields.first_name.readonly = false;
|
||||
UserForm.fields.first_name.editRequired = true;
|
||||
UserForm.fields.last_name.readonly = false;
|
||||
UserForm.fields.last_name.editRequired = true;
|
||||
UserForm.fields.email.readonly = false;
|
||||
UserForm.fields.email.editRequired = true;
|
||||
UserForm.fields.organization.awRequiredWhen = {
|
||||
variable: "orgrequired",
|
||||
init: true
|
||||
};
|
||||
UserForm.fields.organization.readonly = false;
|
||||
UserForm.fields.username.awRequiredWhen = {
|
||||
variable: "not_ldap_user",
|
||||
init: true
|
||||
};
|
||||
UserForm.fields.username.readonly = false;
|
||||
UserForm.fields.password.editRequired = false;
|
||||
UserForm.fields.password.addRrequired = true;
|
||||
};
|
||||
}
|
||||
]);
|
||||
|
||||
@ -3,87 +3,89 @@
|
||||
*
|
||||
* APIDefaults
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('APIDefaults', ['RestServices', 'Utilities'])
|
||||
.factory('GetAPIDefaults', ['Alert', 'Rest', '$rootScope', function(Alert, Rest, $rootScope) {
|
||||
return function(key) {
|
||||
|
||||
//Reload a related collection on pagination or search change
|
||||
|
||||
var answer;
|
||||
var result = {};
|
||||
var cnt=0;
|
||||
'use strict';
|
||||
|
||||
function lookup(key) {
|
||||
var result = {};
|
||||
for (id in $rootScope.apiDefaults) {
|
||||
if (id == key || id.iterator == key) {
|
||||
result[id] = defaults[id];
|
||||
break;
|
||||
}
|
||||
angular.module('APIDefaults', ['RestServices', 'Utilities'])
|
||||
.factory('GetAPIDefaults', ['Alert', 'Rest', '$rootScope',
|
||||
function (Alert, Rest, $rootScope) {
|
||||
return function (key) {
|
||||
|
||||
//Reload a related collection on pagination or search change
|
||||
|
||||
var result = {}, cnt = 0, url;
|
||||
|
||||
function lookup(key) {
|
||||
var id, result = {};
|
||||
for (id in $rootScope.apiDefaults) {
|
||||
if (id === key || id.iterator === key) {
|
||||
result[id] = $rootScope.apiDefaults[id];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function wait() {
|
||||
if ($.isEmptyObject(result) && cnt < 5) {
|
||||
cnt++;
|
||||
setTimeout(1000, wait());
|
||||
} else if (result.status === 'success') {
|
||||
return lookup(key);
|
||||
}
|
||||
}
|
||||
|
||||
if ($rootScope.apiDefaults === null || $rootScope.apiDefaults === undefined) {
|
||||
url = '/api/v1/';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
var id, defaults = data;
|
||||
for (id in defaults) {
|
||||
switch (id) {
|
||||
case 'organizations':
|
||||
defaults[id].iterator = 'organization';
|
||||
break;
|
||||
case 'jobs':
|
||||
defaults[id].iterator = 'job';
|
||||
break;
|
||||
case 'users':
|
||||
defaults[id].iterator = 'user';
|
||||
break;
|
||||
case 'teams':
|
||||
defaults[id].iterator = 'team';
|
||||
break;
|
||||
case 'hosts':
|
||||
defaults[id].iterator = 'host';
|
||||
break;
|
||||
case 'groups':
|
||||
defaults[id].iterator = 'group';
|
||||
break;
|
||||
case 'projects':
|
||||
defaults[id].iterator = 'project';
|
||||
break;
|
||||
case 'inventories':
|
||||
defaults[id].iterator = 'inventory';
|
||||
break;
|
||||
}
|
||||
}
|
||||
$rootScope.apiDefaults = defaults;
|
||||
result = {
|
||||
status: 'success'
|
||||
};
|
||||
})
|
||||
.error(function (data, status) {
|
||||
result = {
|
||||
status: 'error',
|
||||
msg: 'Call to ' + url + ' failed. GET returned status: ' + status
|
||||
};
|
||||
});
|
||||
return wait();
|
||||
} else {
|
||||
return lookup(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function wait() {
|
||||
var answer;
|
||||
if ( result == {} && cnt < 5) {
|
||||
cnt++;
|
||||
setTimeout(1000, wait());
|
||||
}
|
||||
else {
|
||||
if (result.status == 'success') {
|
||||
return lookup(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($rootScope.apiDefaults == null || $rootScope.apiDefaults == undefined) {
|
||||
var result = {};
|
||||
var url = '/api/v1';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
defaults = data;
|
||||
for (var id in defaults) {
|
||||
switch (id) {
|
||||
case 'organizations':
|
||||
dafaults[id].iterator = 'organization';
|
||||
break;
|
||||
case 'jobs':
|
||||
defaults[id].iterator = 'job';
|
||||
break;
|
||||
case 'users':
|
||||
defaults[id].iterator = 'user';
|
||||
break;
|
||||
case 'teams':
|
||||
defaults[id].iterator = 'team';
|
||||
break;
|
||||
case 'hosts':
|
||||
defaults[id].iterator = 'host';
|
||||
break;
|
||||
case 'groups':
|
||||
defaults[id].iterator = 'group';
|
||||
break;
|
||||
case 'projects':
|
||||
defaults[id].iterator = 'project';
|
||||
break;
|
||||
}
|
||||
}
|
||||
$rootScope.apiDefaults = defaults;
|
||||
result = {status: 'success'};
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
result = {status: 'error', msg: 'Call to ' + url + ' failed. GET returned status: ' + status};
|
||||
});
|
||||
return wait();
|
||||
}
|
||||
else {
|
||||
return lookup(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}]);
|
||||
]);
|
||||
@ -5,250 +5,250 @@
|
||||
* Routines for building the tree. Everything related to the tree is here except
|
||||
* for the menu piece. The routine for building the menu is in InventoriesEdit controller
|
||||
* (controllers/Inventories.js)
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationListDefinition', 'ListGenerator', 'AuthService',
|
||||
'InventoryHelper', 'InventoryFormDefinition', 'ParseHelper', 'SearchHelper'
|
||||
])
|
||||
|
||||
.factory('WatchInventoryWindowResize', ['ApplyEllipsis', function(ApplyEllipsis) {
|
||||
return function() {
|
||||
// Call to set or restore window resize
|
||||
var timeOut;
|
||||
$(window).resize(function() {
|
||||
clearTimeout(timeOut);
|
||||
timeOut = setTimeout(function() {
|
||||
// Hack to stop group-name div slipping to a new line
|
||||
$('#groups_table .name-column').each( function() {
|
||||
var td_width = $(this).width();
|
||||
var level_width = $(this).find('.level').width();
|
||||
var level_padding = parseInt($(this).find('.level').css('padding-left').replace(/px/,''));
|
||||
var level = level_width + level_padding;
|
||||
var pct = ( 100 - Math.ceil((level / td_width)*100) ) + '%';
|
||||
$(this).find('.group-name').css({ width: pct });
|
||||
/* globals console:false */
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('InventoryHelper', ['RestServices', 'Utilities', 'OrganizationListDefinition', 'ListGenerator', 'AuthService',
|
||||
'InventoryHelper', 'InventoryFormDefinition', 'ParseHelper', 'SearchHelper'
|
||||
])
|
||||
|
||||
.factory('WatchInventoryWindowResize', ['ApplyEllipsis',
|
||||
function (ApplyEllipsis) {
|
||||
return function () {
|
||||
// Call to set or restore window resize
|
||||
var timeOut;
|
||||
$(window).resize(function () {
|
||||
clearTimeout(timeOut);
|
||||
timeOut = setTimeout(function () {
|
||||
// Hack to stop group-name div slipping to a new line
|
||||
$('#groups_table .name-column').each(function () {
|
||||
var td_width = $(this).width(),
|
||||
level_width = $(this).find('.level').width(),
|
||||
level_padding = parseInt($(this).find('.level').css('padding-left').replace(/px/, '')),
|
||||
level = level_width + level_padding,
|
||||
pct = (100 - Math.ceil((level / td_width) * 100)) + '%';
|
||||
$(this).find('.group-name').css({ width: pct });
|
||||
});
|
||||
ApplyEllipsis('#groups_table .group-name a');
|
||||
ApplyEllipsis('#hosts_table .host-name a');
|
||||
ApplyEllipsis('#groups_table .group-name a');
|
||||
ApplyEllipsis('#hosts_table .host-name a');
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
}])
|
||||
});
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
.factory('SaveInventory', ['InventoryForm', 'Rest', 'Alert', 'ProcessErrors', 'LookUpInit', 'OrganizationList',
|
||||
'GetBasePath', 'ParseTypeChange', 'Wait',
|
||||
function(InventoryForm, Rest, Alert, ProcessErrors, LookUpInit, OrganizationList, GetBasePath, ParseTypeChange, Wait) {
|
||||
return function(params) {
|
||||
|
||||
// Save inventory property modifications
|
||||
.factory('SaveInventory', ['InventoryForm', 'Rest', 'Alert', 'ProcessErrors', 'LookUpInit', 'OrganizationList',
|
||||
'GetBasePath', 'ParseTypeChange', 'Wait',
|
||||
function (InventoryForm, Rest, Alert, ProcessErrors, LookUpInit, OrganizationList, GetBasePath, ParseTypeChange, Wait) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope;
|
||||
|
||||
var form = InventoryForm;
|
||||
var defaultUrl=GetBasePath('inventory');
|
||||
// Save inventory property modifications
|
||||
|
||||
Wait('start');
|
||||
|
||||
try {
|
||||
// Make sure we have valid variable data
|
||||
if (scope.inventoryParseType == 'json') {
|
||||
var json_data = JSON.parse(scope.inventory_variables); //make sure JSON parses
|
||||
}
|
||||
else {
|
||||
var json_data = jsyaml.load(scope.inventory_variables); //parse yaml
|
||||
}
|
||||
var scope = params.scope,
|
||||
form = InventoryForm,
|
||||
defaultUrl = GetBasePath('inventory'),
|
||||
fld, json_data, data;
|
||||
|
||||
// Make sure our JSON is actually an object
|
||||
if (typeof json_data !== 'object') {
|
||||
throw "failed to return an object!";
|
||||
}
|
||||
Wait('start');
|
||||
|
||||
var data = {}
|
||||
for (var fld in form.fields) {
|
||||
if (fld != 'inventory_variables') {
|
||||
if (form.fields[fld].realName) {
|
||||
data[form.fields[fld].realName] = scope[fld];
|
||||
}
|
||||
else {
|
||||
data[fld] = scope[fld];
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
// Make sure we have valid variable data
|
||||
if (scope.inventoryParseType === 'json') {
|
||||
json_data = JSON.parse(scope.inventory_variables); //make sure JSON parses
|
||||
} else {
|
||||
json_data = jsyaml.load(scope.inventory_variables); //parse yaml
|
||||
}
|
||||
|
||||
Rest.setUrl(defaultUrl + scope['inventory_id'] + '/');
|
||||
Rest.put(data)
|
||||
.success( function(data, status, headers, config) {
|
||||
if (scope.inventory_variables) {
|
||||
Rest.setUrl(data.related.variable_data);
|
||||
Rest.put(json_data)
|
||||
.success( function(data, status, headers, config) {
|
||||
Wait('stop');
|
||||
scope.$emit('InventorySaved');
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to update inventory varaibles. PUT returned status: ' + status });
|
||||
});
|
||||
}
|
||||
else {
|
||||
scope.$emit('InventorySaved');
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to update inventory. POST returned status: ' + status });
|
||||
});
|
||||
}
|
||||
catch(err) {
|
||||
Wait('stop');
|
||||
Alert("Error", "Error parsing inventory variables. Parser returned: " + err);
|
||||
}
|
||||
}
|
||||
}])
|
||||
// Make sure our JSON is actually an object
|
||||
if (typeof json_data !== 'object') {
|
||||
throw "failed to return an object!";
|
||||
}
|
||||
|
||||
|
||||
.factory('EditInventoryProperties', ['InventoryForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LookUpInit', 'OrganizationList',
|
||||
'GetBasePath', 'ParseTypeChange', 'SaveInventory', 'Wait', 'Store', 'SearchInit',
|
||||
function(InventoryForm, GenerateForm, Rest, Alert, ProcessErrors, LookUpInit, OrganizationList, GetBasePath, ParseTypeChange, SaveInventory,
|
||||
Wait, Store, SearchInit) {
|
||||
return function(params) {
|
||||
|
||||
var parent_scope = params.scope
|
||||
var inventory_id = params.inventory_id;
|
||||
|
||||
var generator = GenerateForm;
|
||||
var form = InventoryForm;
|
||||
var defaultUrl=GetBasePath('inventory');
|
||||
var master = {};
|
||||
|
||||
// Hang onto current search params
|
||||
var PreviousSearchParams = Store('CurrentSearchParams');
|
||||
|
||||
form.well = false;
|
||||
|
||||
var scope = generator.inject(form, {mode: 'edit', modal: true, related: false, modal_show: false });
|
||||
|
||||
/* Reset form properties. Otherwise it screws up future requests of the Inventories detail page */
|
||||
form.well = true;
|
||||
|
||||
ParseTypeChange(scope,'inventory_variables', 'inventoryParseType');
|
||||
scope.inventoryParseType = 'yaml';
|
||||
scope.formModalActionLabel = 'Save';
|
||||
scope.formModalCancelShow = true;
|
||||
scope.formModalInfo = false;
|
||||
scope.formModalHeader = 'Inventory Properties';
|
||||
|
||||
Wait('start');
|
||||
Rest.setUrl(GetBasePath('inventory') + inventory_id + '/');
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
for (var fld in form.fields) {
|
||||
if (fld == 'inventory_variables') {
|
||||
// Parse variables, converting to YAML.
|
||||
if ($.isEmptyObject(data.variables) || data.variables == "\{\}" ||
|
||||
data.variables == "null" || data.variables == "") {
|
||||
scope.inventory_variables = "---";
|
||||
data = {};
|
||||
for (fld in form.fields) {
|
||||
if (fld !== 'inventory_variables') {
|
||||
if (form.fields[fld].realName) {
|
||||
data[form.fields[fld].realName] = scope[fld];
|
||||
} else {
|
||||
data[fld] = scope[fld];
|
||||
}
|
||||
else {
|
||||
try {
|
||||
var json_obj = JSON.parse(data.variables);
|
||||
scope.inventory_variables = jsyaml.safeDump(json_obj);
|
||||
}
|
||||
catch(err) {
|
||||
Alert('Variable Parse Error', 'Attempted to parse variables for inventory: ' + inventory_id +
|
||||
'. Parse returned: ' + err);
|
||||
if (console) {
|
||||
console.log(err);
|
||||
console.log('data:');
|
||||
console.log(data.variables);
|
||||
}
|
||||
scope.inventory_variables = '---';
|
||||
}
|
||||
}
|
||||
master.inventory_variables = scope.variables;
|
||||
}
|
||||
else if (fld == 'inventory_name') {
|
||||
scope[fld] = data.name;
|
||||
master[fld] = scope[fld];
|
||||
}
|
||||
else if (fld == 'inventory_description') {
|
||||
scope[fld] = data.description;
|
||||
master[fld] = scope[fld];
|
||||
}
|
||||
else if (data[fld]) {
|
||||
scope[fld] = data[fld];
|
||||
master[fld] = scope[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];
|
||||
}
|
||||
}
|
||||
|
||||
LookUpInit({
|
||||
scope: scope,
|
||||
form: form,
|
||||
current_item: scope.organization,
|
||||
list: OrganizationList,
|
||||
field: 'organization'
|
||||
});
|
||||
|
||||
Rest.setUrl(defaultUrl + scope.inventory_id + '/');
|
||||
Rest.put(data)
|
||||
.success(function (data) {
|
||||
if (scope.inventory_variables) {
|
||||
Rest.setUrl(data.related.variable_data);
|
||||
Rest.put(json_data)
|
||||
.success(function () {
|
||||
Wait('stop');
|
||||
scope.$emit('InventorySaved');
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, form, { hdr: 'Error!',
|
||||
msg: 'Failed to update inventory varaibles. PUT returned status: ' + status
|
||||
});
|
||||
});
|
||||
} else {
|
||||
scope.$emit('InventorySaved');
|
||||
}
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, form, { hdr: 'Error!',
|
||||
msg: 'Failed to update inventory. POST returned status: ' + status });
|
||||
});
|
||||
} catch (err) {
|
||||
Wait('stop');
|
||||
$('#form-modal').modal('show');
|
||||
Alert("Error", "Error parsing inventory variables. Parser returned: " + err);
|
||||
}
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
.factory('EditInventoryProperties', ['InventoryForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LookUpInit', 'OrganizationList',
|
||||
'GetBasePath', 'ParseTypeChange', 'SaveInventory', 'Wait', 'Store', 'SearchInit',
|
||||
function (InventoryForm, GenerateForm, Rest, Alert, ProcessErrors, LookUpInit, OrganizationList, GetBasePath, ParseTypeChange, SaveInventory,
|
||||
Wait, Store, SearchInit) {
|
||||
return function (params) {
|
||||
|
||||
var parent_scope = params.scope,
|
||||
inventory_id = params.inventory_id,
|
||||
generator = GenerateForm,
|
||||
form = InventoryForm,
|
||||
master = {},
|
||||
PreviousSearchParams = Store('CurrentSearchParams'),
|
||||
scope;
|
||||
|
||||
form.well = false;
|
||||
scope = generator.inject(form, { mode: 'edit', modal: true, related: false, modal_show: false });
|
||||
|
||||
/* Reset form properties. Otherwise it screws up future requests of the Inventories detail page */
|
||||
form.well = true;
|
||||
|
||||
ParseTypeChange(scope, 'inventory_variables', 'inventoryParseType');
|
||||
scope.inventoryParseType = 'yaml';
|
||||
scope.formModalActionLabel = 'Save';
|
||||
scope.formModalCancelShow = true;
|
||||
scope.formModalInfo = false;
|
||||
scope.formModalHeader = 'Inventory Properties';
|
||||
|
||||
Wait('start');
|
||||
Rest.setUrl(GetBasePath('inventory') + inventory_id + '/');
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
var fld, json_obj;
|
||||
for (fld in form.fields) {
|
||||
if (fld === 'inventory_variables') {
|
||||
// Parse variables, converting to YAML.
|
||||
if ($.isEmptyObject(data.variables) || data.variables === "{}" ||
|
||||
data.variables === "null" || data.variables === "") {
|
||||
scope.inventory_variables = "---";
|
||||
} else {
|
||||
try {
|
||||
json_obj = JSON.parse(data.variables);
|
||||
scope.inventory_variables = jsyaml.safeDump(json_obj);
|
||||
} catch (err) {
|
||||
Alert('Variable Parse Error', 'Attempted to parse variables for inventory: ' + inventory_id +
|
||||
'. Parse returned: ' + err);
|
||||
if (console) {
|
||||
console.log(err);
|
||||
console.log('data:');
|
||||
console.log(data.variables);
|
||||
}
|
||||
scope.inventory_variables = '---';
|
||||
}
|
||||
}
|
||||
master.inventory_variables = scope.variables;
|
||||
} else if (fld === 'inventory_name') {
|
||||
scope[fld] = data.name;
|
||||
master[fld] = scope[fld];
|
||||
} else if (fld === 'inventory_description') {
|
||||
scope[fld] = data.description;
|
||||
master[fld] = scope[fld];
|
||||
} else if (data[fld]) {
|
||||
scope[fld] = data[fld];
|
||||
master[fld] = scope[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];
|
||||
}
|
||||
}
|
||||
|
||||
LookUpInit({
|
||||
scope: scope,
|
||||
form: form,
|
||||
current_item: scope.organization,
|
||||
list: OrganizationList,
|
||||
field: 'organization'
|
||||
});
|
||||
|
||||
Wait('stop');
|
||||
$('#form-modal').modal('show');
|
||||
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to get inventory: ' + inventory_id + '. GET returned: ' + status });
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to get inventory: ' + inventory_id + '. GET returned: ' + status
|
||||
});
|
||||
});
|
||||
|
||||
if (scope.removeInventorySaved) {
|
||||
scope.removeInventorySaved();
|
||||
}
|
||||
scope.removeInventorySaved = scope.$on('InventorySaved', function() {
|
||||
$('#form-modal').modal('hide');
|
||||
// Restore prior search state
|
||||
if (scope.searchCleanp) {
|
||||
scope.searchCleanup();
|
||||
|
||||
if (scope.removeInventorySaved) {
|
||||
scope.removeInventorySaved();
|
||||
}
|
||||
SearchInit({
|
||||
scope: parent_scope,
|
||||
set: PreviousSearchParams.set,
|
||||
list: PreviousSearchParams.list,
|
||||
url: PreviousSearchParams.defaultUrl,
|
||||
iterator: PreviousSearchParams.iterator,
|
||||
sort_order: PreviousSearchParams.sort_order,
|
||||
setWidgets: false
|
||||
scope.removeInventorySaved = scope.$on('InventorySaved', function () {
|
||||
$('#form-modal').modal('hide');
|
||||
// Restore prior search state
|
||||
if (scope.searchCleanp) {
|
||||
scope.searchCleanup();
|
||||
}
|
||||
SearchInit({
|
||||
scope: parent_scope,
|
||||
set: PreviousSearchParams.set,
|
||||
list: PreviousSearchParams.list,
|
||||
url: PreviousSearchParams.defaultUrl,
|
||||
iterator: PreviousSearchParams.iterator,
|
||||
sort_order: PreviousSearchParams.sort_order,
|
||||
setWidgets: false
|
||||
});
|
||||
parent_scope.$emit('RefreshInventories');
|
||||
parent_scope.$emit('RefreshInventories');
|
||||
});
|
||||
|
||||
scope.cancelModal = function() {
|
||||
// Restore prior search state
|
||||
if (scope.searchCleanp) {
|
||||
scope.searchCleanup();
|
||||
}
|
||||
SearchInit({
|
||||
scope: parent_scope,
|
||||
set: PreviousSearchParams.set,
|
||||
list: PreviousSearchParams.list,
|
||||
url: PreviousSearchParams.defaultUrl,
|
||||
iterator: PreviousSearchParams.iterator,
|
||||
sort_order: PreviousSearchParams.sort_order,
|
||||
setWidgets: false
|
||||
scope.cancelModal = function () {
|
||||
// Restore prior search state
|
||||
if (scope.searchCleanp) {
|
||||
scope.searchCleanup();
|
||||
}
|
||||
SearchInit({
|
||||
scope: parent_scope,
|
||||
set: PreviousSearchParams.set,
|
||||
list: PreviousSearchParams.list,
|
||||
url: PreviousSearchParams.defaultUrl,
|
||||
iterator: PreviousSearchParams.iterator,
|
||||
sort_order: PreviousSearchParams.sort_order,
|
||||
setWidgets: false
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
scope.formModalAction = function() {
|
||||
parent_scope.inventory_id = inventory_id;
|
||||
parent_scope.inventory_name = scope.inventory_name;
|
||||
SaveInventory({ scope: scope });
|
||||
}
|
||||
|
||||
}
|
||||
}]);
|
||||
scope.formModalAction = function () {
|
||||
parent_scope.inventory_id = inventory_id;
|
||||
parent_scope.inventory_name = scope.inventory_name;
|
||||
SaveInventory({
|
||||
scope: scope
|
||||
});
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -8,33 +8,33 @@
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('md5Helper', ['RestServices', 'Utilities'])
|
||||
.factory('md5Setup', ['Alert', 'Rest', 'GetBasePath','ProcessErrors',
|
||||
function(Alert, Rest, GetBasePath, ProcessErrors) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var master = params.master;
|
||||
var check_field = params.check_field;
|
||||
var default_val = params.default_val; //default(true/false) for the checkbox
|
||||
|
||||
scope[check_field] = default_val;
|
||||
master[check_field] = default_val;
|
||||
'use strict';
|
||||
|
||||
scope.genMD5 = function(fld) {
|
||||
var now = new Date();
|
||||
scope[fld] = $.md5('AnsibleWorks' + now.getTime());
|
||||
}
|
||||
angular.module('md5Helper', ['RestServices', 'Utilities'])
|
||||
.factory('md5Setup', [ function () {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
master = params.master,
|
||||
check_field = params.check_field,
|
||||
default_val = params.default_val;
|
||||
|
||||
scope.toggleCallback = function(fld) {
|
||||
if (scope.allow_callbacks == 'false') {
|
||||
scope[fld] = '';
|
||||
}
|
||||
}
|
||||
scope[check_field] = default_val;
|
||||
master[check_field] = default_val;
|
||||
|
||||
scope.selectAll = function(fld) {
|
||||
$('input[name="' + fld +'"]').focus().select();
|
||||
}
|
||||
|
||||
}
|
||||
}]);
|
||||
scope.genMD5 = function (fld) {
|
||||
var now = new Date();
|
||||
scope[fld] = $.md5('AnsibleWorks' + now.getTime());
|
||||
};
|
||||
|
||||
scope.toggleCallback = function (fld) {
|
||||
if (scope.allow_callbacks === 'false') {
|
||||
scope[fld] = '';
|
||||
}
|
||||
};
|
||||
|
||||
scope.selectAll = function (fld) {
|
||||
$('input[name="' + fld + '"]').focus().select();
|
||||
};
|
||||
};
|
||||
}]);
|
||||
@ -9,35 +9,43 @@
|
||||
* scope: <current scope>,
|
||||
* set: <model>,
|
||||
* iterator: <model name in singular form (i.e. organization),
|
||||
* url: <the api url to call>
|
||||
* });
|
||||
* url: <the api url to call>
|
||||
* });
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('RefreshRelatedHelper', ['RestServices', 'Utilities', 'PaginationHelpers'])
|
||||
.factory('RefreshRelated', ['ProcessErrors', 'Rest', 'Wait', 'PageRangeSetup',
|
||||
function(ProcessErrors, Rest, Wait, PageRangeSetup) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var set = params.set;
|
||||
var iterator = params.iterator;
|
||||
var url = params.url;
|
||||
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
PageRangeSetup({ scope: scope, count: data.count, next: data.next, previous: data.previous, iterator: iterator });
|
||||
scope[set] = data['results'];
|
||||
scope[iterator + 'Loading'] = false;
|
||||
scope[iterator + 'HoldInput'] = false;
|
||||
Wait('stop');
|
||||
scope.$emit('related' + set);
|
||||
|
||||
})
|
||||
.error ( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to retrieve ' + set + '. GET returned status: ' + status });
|
||||
});
|
||||
'use strict';
|
||||
|
||||
angular.module('RefreshRelatedHelper', ['RestServices', 'Utilities', 'PaginationHelpers'])
|
||||
.factory('RefreshRelated', ['ProcessErrors', 'Rest', 'Wait', 'PageRangeSetup',
|
||||
function (ProcessErrors, Rest, Wait, PageRangeSetup) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
set = params.set,
|
||||
iterator = params.iterator,
|
||||
url = params.url;
|
||||
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
PageRangeSetup({
|
||||
scope: scope,
|
||||
count: data.count,
|
||||
next: data.next,
|
||||
previous: data.previous,
|
||||
iterator: iterator
|
||||
});
|
||||
scope[set] = data.results;
|
||||
scope[iterator + 'Loading'] = false;
|
||||
scope[iterator + 'HoldInput'] = false;
|
||||
Wait('stop');
|
||||
scope.$emit('related' + set);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to retrieve ' + set + '. GET returned status: ' + status });
|
||||
});
|
||||
};
|
||||
}
|
||||
}]);
|
||||
]);
|
||||
@ -9,40 +9,52 @@
|
||||
* scope: <current scope>,
|
||||
* set: <model>,
|
||||
* iterator: <model name in singular form (i.e. organization),
|
||||
* url: <the api url to call>
|
||||
* });
|
||||
* url: <the api url to call>
|
||||
* });
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('RefreshHelper', ['RestServices', 'Utilities', 'PaginationHelpers'])
|
||||
.factory('Refresh', ['ProcessErrors', 'Rest', 'Wait', 'Empty', 'PageRangeSetup',
|
||||
function(ProcessErrors, Rest, Wait, Empty, PageRangeSetup) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var set = params.set;
|
||||
var iterator = params.iterator;
|
||||
var url = params.url;
|
||||
|
||||
scope.current_url = url;
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
PageRangeSetup({ scope: scope, count: data.count, next: data.next, previous: data.previous, iterator: iterator });
|
||||
scope[iterator + 'Loading'] = false;
|
||||
for (var i=1; i <= 3; i++) {
|
||||
var modifier = (i == 1) ? '' : i;
|
||||
scope[iterator + 'HoldInput' + modifier] = false;
|
||||
}
|
||||
scope[set] = data['results'];
|
||||
window.scrollTo(0,0);
|
||||
Wait('stop');
|
||||
scope.$emit('PostRefresh');
|
||||
})
|
||||
.error ( function(data, status, headers, config) {
|
||||
scope[iterator + 'HoldInput'] = false;
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to retrieve ' + set + '. GET returned status: ' + status });
|
||||
});
|
||||
'use strict';
|
||||
|
||||
angular.module('RefreshHelper', ['RestServices', 'Utilities', 'PaginationHelpers'])
|
||||
.factory('Refresh', ['ProcessErrors', 'Rest', 'Wait', 'Empty', 'PageRangeSetup',
|
||||
function (ProcessErrors, Rest, Wait, Empty, PageRangeSetup) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
set = params.set,
|
||||
iterator = params.iterator,
|
||||
url = params.url;
|
||||
|
||||
scope.current_url = url;
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
var i, modifier;
|
||||
PageRangeSetup({
|
||||
scope: scope,
|
||||
count: data.count,
|
||||
next: data.next,
|
||||
previous: data.previous,
|
||||
iterator: iterator
|
||||
});
|
||||
scope[iterator + 'Loading'] = false;
|
||||
for (i = 1; i <= 3; i++) {
|
||||
modifier = (i === 1) ? '' : i;
|
||||
scope[iterator + 'HoldInput' + modifier] = false;
|
||||
}
|
||||
scope[set] = data.results;
|
||||
window.scrollTo(0, 0);
|
||||
Wait('stop');
|
||||
scope.$emit('PostRefresh');
|
||||
})
|
||||
.error(function (data, status) {
|
||||
scope[iterator + 'HoldInput'] = false;
|
||||
ProcessErrors(scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to retrieve ' + set + '. GET returned status: ' + status
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
}]);
|
||||
]);
|
||||
@ -3,247 +3,241 @@
|
||||
*
|
||||
* RelatedSearchHelper
|
||||
*
|
||||
* All the parts for controlling the search widget on
|
||||
* All the parts for controlling the search widget on
|
||||
* related collections.
|
||||
*
|
||||
* SearchInit({
|
||||
* scope: <scope>,
|
||||
* relatedSets: <array of related collections {model_name, url, iterator}>,
|
||||
* form: <form object used by FormGenerator>
|
||||
* });
|
||||
* });
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('RelatedSearchHelper', ['RestServices', 'Utilities','RefreshRelatedHelper'])
|
||||
'use strict';
|
||||
|
||||
angular.module('RelatedSearchHelper', ['RestServices', 'Utilities', 'RefreshRelatedHelper'])
|
||||
.factory('RelatedSearchInit', ['$timeout', 'Alert', 'Rest', 'RefreshRelated', 'Wait',
|
||||
function($timeout, Alert, Rest, RefreshRelated, Wait) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var relatedSets = params.relatedSets;
|
||||
var form = params.form;
|
||||
|
||||
// Set default values
|
||||
function setDefaults(inIterator) {
|
||||
var iterator, f;
|
||||
for (var set in form.related) {
|
||||
if (form.related[set].type != 'tree' && (inIterator === undefined || inIterator == form.related[set].iterator)) {
|
||||
iterator = form.related[set].iterator;
|
||||
for (var fld in form.related[set].fields) {
|
||||
if (form.related[set].fields[fld].key) {
|
||||
scope[iterator + 'SearchField'] = fld
|
||||
scope[iterator + 'SearchFieldLabel'] = form.related[set].fields[fld].label;
|
||||
break;
|
||||
function ($timeout, Alert, Rest, RefreshRelated, Wait) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
relatedSets = params.relatedSets,
|
||||
form = params.form, f;
|
||||
|
||||
// Set default values
|
||||
function setDefaults(inIterator) {
|
||||
var iterator, f, fld, set;
|
||||
for (set in form.related) {
|
||||
if (form.related[set].type !== 'tree' && (inIterator === undefined || inIterator === form.related[set].iterator)) {
|
||||
iterator = form.related[set].iterator;
|
||||
for (fld in form.related[set].fields) {
|
||||
if (form.related[set].fields[fld].key) {
|
||||
scope[iterator + 'SearchField'] = fld;
|
||||
scope[iterator + 'SearchFieldLabel'] = form.related[set].fields[fld].label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
scope[iterator + 'SortOrder'] = null;
|
||||
scope[iterator + 'SearchType'] = 'icontains';
|
||||
scope[iterator + 'SearchTypeLabel'] = 'Contains';
|
||||
scope[iterator + 'SearchValue'] = null;
|
||||
scope[iterator + 'SelectShow'] = false;
|
||||
//scope[iterator + 'HideSearchType'] = false;
|
||||
scope[iterator + 'ShowStartBtn'] = true;
|
||||
scope[iterator + 'HideAllStartBtn'] = false;
|
||||
|
||||
f = scope[iterator + 'SearchField'];
|
||||
if (form.related[set].fields[f].searchType &&
|
||||
(form.related[set].fields[f].searchType === 'boolean' || form.related[set].fields[f].searchType === 'select')) {
|
||||
scope[iterator + 'SelectShow'] = true;
|
||||
scope[iterator + 'SearchSelectOpts'] = form.fields[f].searchOptions;
|
||||
}
|
||||
if (form.related[set].fields[f].searchType && form.related[set].fields[f].searchType === 'gtzero') {
|
||||
scope[iterator + "InputHide"] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
scope[iterator + 'SortOrder'] = null;
|
||||
scope[iterator + 'SearchType'] = 'icontains';
|
||||
scope[iterator + 'SearchTypeLabel'] = 'Contains';
|
||||
scope[iterator + 'SearchValue'] = null;
|
||||
}
|
||||
|
||||
setDefaults();
|
||||
|
||||
scope.resetSearch = function (iterator) {
|
||||
setDefaults(iterator);
|
||||
scope.search(iterator);
|
||||
};
|
||||
|
||||
// Functions to handle search widget changes
|
||||
scope.setSearchField = function (iterator, fld, label) {
|
||||
|
||||
var f, related;
|
||||
|
||||
for (related in form.related) {
|
||||
if (form.related[related].iterator === iterator) {
|
||||
f = form.related[related].fields[fld];
|
||||
}
|
||||
}
|
||||
|
||||
scope[iterator + 'SearchFieldLabel'] = label;
|
||||
scope[iterator + 'SearchField'] = fld;
|
||||
scope[iterator + 'SearchValue'] = '';
|
||||
scope[iterator + 'SelectShow'] = false;
|
||||
//scope[iterator + 'HideSearchType'] = false;
|
||||
scope[iterator + 'InputHide'] = false;
|
||||
scope[iterator + 'ShowStartBtn'] = true;
|
||||
scope[iterator + 'HideAllStartBtn'] = false;
|
||||
|
||||
f = scope[iterator + 'SearchField']
|
||||
if (form.related[set].fields[f].searchType && ( form.related[set].fields[f].searchType == 'boolean'
|
||||
|| form.related[set].fields[f].searchType == 'select')) {
|
||||
scope[iterator + 'SelectShow'] = true;
|
||||
scope[iterator + 'SearchSelectOpts'] = list.fields[f].searchOptions;
|
||||
if (f.searchType !== undefined && f.searchType === 'gtzero') {
|
||||
scope[iterator + "InputHide"] = true;
|
||||
scope[iterator + 'ShowStartBtn'] = false;
|
||||
}
|
||||
if (form.related[set].fields[f].searchType && form.related[set].fields[f].searchType == 'gtzero') {
|
||||
scope[iterator + "InputHide"] = true;
|
||||
if (f.searchType !== undefined && (f.searchType === 'boolean' || f.searchType === 'select')) {
|
||||
scope[iterator + 'SelectShow'] = true;
|
||||
scope[iterator + 'SearchSelectOpts'] = f.searchOptions;
|
||||
}
|
||||
if (f.searchType !== undefined && f.searchType === 'int') {
|
||||
//scope[iterator + 'HideSearchType'] = true;
|
||||
scope[iterator + 'SearchType'] = 'int';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setDefaults();
|
||||
scope.search(iterator);
|
||||
|
||||
scope.resetSearch = function(iterator) {
|
||||
setDefaults(iterator);
|
||||
scope.search(iterator);
|
||||
}
|
||||
|
||||
// Functions to handle search widget changes
|
||||
scope.setSearchField = function(iterator, fld, label) {
|
||||
|
||||
for (var related in form.related) {
|
||||
if ( form.related[related].iterator == iterator ) {
|
||||
var f = form.related[related].fields[fld];
|
||||
}
|
||||
}
|
||||
|
||||
scope[iterator + 'SearchFieldLabel'] = label;
|
||||
scope[iterator + 'SearchField'] = fld;
|
||||
scope[iterator + 'SearchValue'] = '';
|
||||
scope[iterator + 'SelectShow'] = false;
|
||||
//scope[iterator + 'HideSearchType'] = false;
|
||||
scope[iterator + 'InputHide'] = false;
|
||||
scope[iterator + 'ShowStartBtn'] = true;
|
||||
};
|
||||
|
||||
if (f.searchType !== undefined && f.searchType == 'gtzero') {
|
||||
scope[iterator + "InputHide"] = true;
|
||||
scope[iterator + 'ShowStartBtn'] = false;
|
||||
}
|
||||
if (f.searchType !== undefined && (f.searchType == 'boolean'
|
||||
|| f.searchType == 'select')) {
|
||||
scope[iterator + 'SelectShow'] = true;
|
||||
scope[iterator + 'SearchSelectOpts'] = f.searchOptions;
|
||||
}
|
||||
if (f.searchType !== undefined && f.searchType == 'int') {
|
||||
//scope[iterator + 'HideSearchType'] = true;
|
||||
scope[model + 'SearchType'] = 'int';
|
||||
}
|
||||
scope.setSearchType = function (model, type, label) {
|
||||
scope[model + 'SearchTypeLabel'] = label;
|
||||
scope[model + 'SearchType'] = type;
|
||||
scope.search(model);
|
||||
};
|
||||
|
||||
scope.search(iterator);
|
||||
scope.startSearch = function (e, iterator) {
|
||||
// If use clicks enter while on input field, start the search
|
||||
if (e.keyCode === 13) {
|
||||
scope.search(iterator);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
scope.search = function (iterator) {
|
||||
//scope[iterator + 'SearchSpin'] = true;
|
||||
Wait('start');
|
||||
scope[iterator + 'Loading'] = true;
|
||||
scope[iterator + 'HoldInput'] = true;
|
||||
|
||||
scope.setSearchType = function(model, type, label) {
|
||||
scope[model + 'SearchTypeLabel'] = label;
|
||||
scope[model + 'SearchType'] = type;
|
||||
scope.search(model);
|
||||
}
|
||||
if (scope[iterator + 'SearchValue']) {
|
||||
// User typed a value in input field
|
||||
scope[iterator + 'ShowStartBtn'] = false;
|
||||
}
|
||||
|
||||
scope.startSearch = function(e,iterator) {
|
||||
// If use clicks enter while on input field, start the search
|
||||
if (e.keyCode == 13) {
|
||||
scope.search(iterator);
|
||||
}
|
||||
}
|
||||
if (iterator === 'host') {
|
||||
if (scope.hostSearchField === 'has_active_failures') {
|
||||
if (scope.hostSearchSelectValue && scope.hostSearchSelectValue.value === 1) {
|
||||
scope.hostFailureFilter = true;
|
||||
} else {
|
||||
scope.hostFailureFilter = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope.search = function(iterator) {
|
||||
//scope[iterator + 'SearchSpin'] = true;
|
||||
Wait('start');
|
||||
scope[iterator + 'Loading'] = true;
|
||||
scope[iterator + 'HoldInput'] = true;
|
||||
|
||||
if (scope[iterator + 'SearchValue']) {
|
||||
// User typed a value in input field
|
||||
scope[iterator + 'ShowStartBtn'] = false;
|
||||
}
|
||||
var fld, key, set, url, sort_order;
|
||||
for (key in relatedSets) {
|
||||
if (relatedSets[key].iterator === iterator) {
|
||||
set = key;
|
||||
url = relatedSets[key].url;
|
||||
for (fld in form.related[key].fields) {
|
||||
if (form.related[key].fields[fld].key) {
|
||||
if (form.related[key].fields[fld].desc) {
|
||||
sort_order = '-' + fld;
|
||||
} else {
|
||||
sort_order = fld;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iterator == 'host') {
|
||||
if (scope['hostSearchField'] == 'has_active_failures') {
|
||||
if (scope['hostSearchSelectValue'] && scope['hostSearchSelectValue'].value == 1) {
|
||||
scope['hostFailureFilter'] = true;
|
||||
}
|
||||
else {
|
||||
scope['hostFailureFilter'] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
sort_order = (scope[iterator + 'SortOrder'] === null) ? sort_order : scope[iterator + 'SortOrder'];
|
||||
|
||||
var set, url, iterator, sort_order;
|
||||
for (var key in relatedSets) {
|
||||
if (relatedSets[key].iterator == iterator) {
|
||||
set = key;
|
||||
url = relatedSets[key].url;
|
||||
for (var fld in form.related[key].fields) {
|
||||
if (form.related[key].fields[fld].key) {
|
||||
if (form.related[key].fields[fld].desc) {
|
||||
sort_order = '-' + fld;
|
||||
}
|
||||
else {
|
||||
sort_order = fld;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sort_order = (scope[iterator + 'SortOrder'] == null) ? sort_order : scope[iterator + 'SortOrder'];
|
||||
f = form.related[set].fields[scope[iterator + 'SearchField']];
|
||||
if ((scope[iterator + 'SelectShow'] === false && scope[iterator + 'SearchValue'] !== '' &&
|
||||
scope[iterator + 'SearchValue'] !== undefined) || (scope[iterator + 'SelectShow'] && scope[iterator + 'SearchSelectValue']) ||
|
||||
(f.searchType && f.searchType === 'gtzero')) {
|
||||
if (f.sourceModel) {
|
||||
// handle fields whose source is a related model e.g. inventories.organization
|
||||
scope[iterator + 'SearchParams'] = f.sourceModel + '__' + f.sourceField + '__';
|
||||
} else if (f.searchField) {
|
||||
scope[iterator + 'SearchParams'] = f.searchField + '__';
|
||||
} else {
|
||||
scope[iterator + 'SearchParams'] = scope[iterator + 'SearchField'] + '__';
|
||||
}
|
||||
|
||||
var f = form.related[set].fields[scope[iterator + 'SearchField']];
|
||||
if ( (scope[iterator + 'SelectShow'] == false && scope[iterator + 'SearchValue'] != '' && scope[iterator + 'SearchValue'] != undefined) ||
|
||||
(scope[iterator + 'SelectShow'] && scope[iterator + 'SearchSelectValue']) || (f.searchType && f.searchType == 'gtzero') ) {
|
||||
if (f.sourceModel) {
|
||||
// handle fields whose source is a related model e.g. inventories.organization
|
||||
scope[iterator + 'SearchParams'] = f.sourceModel + '__' + f.sourceField + '__';
|
||||
}
|
||||
else if (f.searchField) {
|
||||
scope[iterator + 'SearchParams'] = f.searchField + '__';
|
||||
}
|
||||
else {
|
||||
scope[iterator + 'SearchParams'] = scope[iterator + 'SearchField'] + '__';
|
||||
}
|
||||
|
||||
if ( f.searchType && (f.searchType == 'int' || f.searchType == 'boolean' ) ) {
|
||||
scope[iterator + 'SearchParams'] += 'int=';
|
||||
}
|
||||
else if ( f.searchType && f.searchType == 'gtzero' ) {
|
||||
scope[iterator + 'SearchParams'] += 'gt=0';
|
||||
}
|
||||
else {
|
||||
scope[iterator + 'SearchParams'] += scope[iterator + 'SearchType'] + '=';
|
||||
}
|
||||
|
||||
if ( f.searchType && (f.searchType == 'boolean' || f.searchType == 'select') ) {
|
||||
scope[iterator + 'SearchParams'] += scope[iterator + 'SearchSelectValue'].value;
|
||||
}
|
||||
else if ( f.searchType == undefined || f.searchType == 'gtzero' ) {
|
||||
scope[iterator + 'SearchParams'] += escape(scope[iterator + 'SearchValue']);
|
||||
}
|
||||
scope[iterator + 'SearchParams'] += (sort_order) ? '&order_by=' + escape(sort_order) : '';
|
||||
}
|
||||
else {
|
||||
scope[iterator + 'SearchParams'] = (sort_order) ? 'order_by=' + escape(sort_order) : '';
|
||||
}
|
||||
scope[iterator + 'Page'] = 0;
|
||||
url += (url.match(/\/$/)) ? '?' : '&';
|
||||
url += scope[iterator + 'SearchParams'];
|
||||
url += (scope[iterator + 'PageSize']) ? '&page_size=' + scope[iterator + 'PageSize'] : "";
|
||||
RefreshRelated({ scope: scope, set: set, iterator: iterator, url: url });
|
||||
}
|
||||
if (f.searchType && (f.searchType === 'int' || f.searchType === 'boolean')) {
|
||||
scope[iterator + 'SearchParams'] += 'int=';
|
||||
} else if (f.searchType && f.searchType === 'gtzero') {
|
||||
scope[iterator + 'SearchParams'] += 'gt=0';
|
||||
} else {
|
||||
scope[iterator + 'SearchParams'] += scope[iterator + 'SearchType'] + '=';
|
||||
}
|
||||
|
||||
if (f.searchType && (f.searchType === 'boolean' || f.searchType === 'select')) {
|
||||
scope[iterator + 'SearchParams'] += scope[iterator + 'SearchSelectValue'].value;
|
||||
} else if (f.searchType === undefined || f.searchType === 'gtzero') {
|
||||
scope[iterator + 'SearchParams'] += encodeURI(scope[iterator + 'SearchValue']);
|
||||
}
|
||||
scope[iterator + 'SearchParams'] += (sort_order) ? '&order_by=' + encodeURI(sort_order) : '';
|
||||
} else {
|
||||
scope[iterator + 'SearchParams'] = (sort_order) ? 'order_by=' + encodeURI(sort_order) : '';
|
||||
}
|
||||
scope[iterator + 'Page'] = 0;
|
||||
url += (url.match(/\/$/)) ? '?' : '&';
|
||||
url += scope[iterator + 'SearchParams'];
|
||||
url += (scope[iterator + 'PageSize']) ? '&page_size=' + scope[iterator + 'PageSize'] : "";
|
||||
RefreshRelated({ scope: scope, set: set, iterator: iterator, url: url });
|
||||
};
|
||||
|
||||
|
||||
scope.sort = function(iterator, fld) {
|
||||
var sort_order;
|
||||
scope.sort = function (iterator, fld) {
|
||||
var sort_order, icon, direction, set;
|
||||
|
||||
// reset sort icons back to 'icon-sort' on all columns
|
||||
// except the one clicked
|
||||
$('.' + iterator + ' .list-header').each(function(index) {
|
||||
if ($(this).attr('id') != iterator + '-' + fld + '-header') {
|
||||
var icon = $(this).find('i');
|
||||
icon.attr('class','icon-sort');
|
||||
}
|
||||
});
|
||||
|
||||
// Toggle the icon for the clicked column
|
||||
// and set the sort direction
|
||||
var icon = $('#' + iterator + '-' + fld + '-header i');
|
||||
var direction = '';
|
||||
if (icon.hasClass('icon-sort')) {
|
||||
icon.removeClass('icon-sort');
|
||||
icon.addClass('icon-sort-up');
|
||||
}
|
||||
else if (icon.hasClass('icon-sort-up')) {
|
||||
icon.removeClass('icon-sort-up');
|
||||
icon.addClass('icon-sort-down');
|
||||
direction = '-';
|
||||
}
|
||||
else if (icon.hasClass('icon-sort-down')) {
|
||||
icon.removeClass('icon-sort-down');
|
||||
icon.addClass('icon-sort-up');
|
||||
}
|
||||
// reset sort icons back to 'icon-sort' on all columns
|
||||
// except the one clicked
|
||||
$('.' + iterator + ' .list-header').each(function () {
|
||||
if ($(this).attr('id') !== iterator + '-' + fld + '-header') {
|
||||
var icon = $(this).find('i');
|
||||
icon.attr('class', 'icon-sort');
|
||||
}
|
||||
});
|
||||
|
||||
// Set the sorder order value and call the API to refresh the list with the new order
|
||||
for (var set in form.related) {
|
||||
if (form.related[set].iterator == iterator) {
|
||||
if (form.related[set].fields[fld].sourceModel) {
|
||||
sort_order = direction + form.related[set].fields[fld].sourceModel + '__' +
|
||||
form.related[set].fields[fld].sourceField;
|
||||
}
|
||||
else {
|
||||
sort_order = direction + fld;
|
||||
}
|
||||
}
|
||||
}
|
||||
scope[iterator + 'SortOrder'] = sort_order;
|
||||
scope.search(iterator);
|
||||
}
|
||||
// Toggle the icon for the clicked column
|
||||
// and set the sort direction
|
||||
icon = $('#' + iterator + '-' + fld + '-header i');
|
||||
direction = '';
|
||||
if (icon.hasClass('icon-sort')) {
|
||||
icon.removeClass('icon-sort');
|
||||
icon.addClass('icon-sort-up');
|
||||
} else if (icon.hasClass('icon-sort-up')) {
|
||||
icon.removeClass('icon-sort-up');
|
||||
icon.addClass('icon-sort-down');
|
||||
direction = '-';
|
||||
} else if (icon.hasClass('icon-sort-down')) {
|
||||
icon.removeClass('icon-sort-down');
|
||||
icon.addClass('icon-sort-up');
|
||||
}
|
||||
|
||||
// Set the sorder order value and call the API to refresh the list with the new order
|
||||
for (set in form.related) {
|
||||
if (form.related[set].iterator === iterator) {
|
||||
if (form.related[set].fields[fld].sourceModel) {
|
||||
sort_order = direction + form.related[set].fields[fld].sourceModel + '__' +
|
||||
form.related[set].fields[fld].sourceField;
|
||||
} else {
|
||||
sort_order = direction + fld;
|
||||
}
|
||||
}
|
||||
}
|
||||
scope[iterator + 'SortOrder'] = sort_order;
|
||||
scope.search(iterator);
|
||||
};
|
||||
};
|
||||
}
|
||||
}]);
|
||||
]);
|
||||
@ -3,7 +3,7 @@
|
||||
*
|
||||
* SearchHelper
|
||||
*
|
||||
* All the parts for controlling the search widget on
|
||||
* All the parts for controlling the search widget on
|
||||
* related collections.
|
||||
*
|
||||
* SearchInit({
|
||||
@ -11,26 +11,122 @@
|
||||
* set: <model name (i.e. organizations) used in ng-repeat>
|
||||
* url: <default api url used to load data>
|
||||
* list: <list object used by ListGenerator>
|
||||
* });
|
||||
* });
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
|
||||
|
||||
.factory('SearchInit', ['Alert', 'Rest', 'Refresh', '$location', 'GetBasePath', 'Empty', '$timeout', 'Wait', 'Store',
|
||||
function(Alert, Rest, Refresh, $location, GetBasePath, Empty, $timeout, Wait, Store) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope,
|
||||
set = params.set,
|
||||
defaultUrl = params.url,
|
||||
list = params.list,
|
||||
iterator = (params.iterator) ? params.iterator : list.iterator,
|
||||
setWidgets = (params.setWidgets === false) ? false : true,
|
||||
sort_order = params.sort_order || '',
|
||||
widgets, i, modifier, current_params;
|
||||
|
||||
/*
|
||||
|
||||
.factory('SearchInit', ['Alert', 'Rest', 'Refresh', '$location', 'GetBasePath', 'Empty', '$timeout', 'Wait', 'Store',
|
||||
function (Alert, Rest, Refresh, $location, GetBasePath, Empty, $timeout, Wait, Store) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
set = params.set,
|
||||
defaultUrl = params.url,
|
||||
list = params.list,
|
||||
iterator = (params.iterator) ? params.iterator : list.iterator,
|
||||
setWidgets = (params.setWidgets === false) ? false : true,
|
||||
sort_order = params.sort_order || '',
|
||||
widgets, i, modifier, current_params;
|
||||
|
||||
function setDefaults(widget) {
|
||||
// Set default values
|
||||
var f, fld, fka, modifier;
|
||||
modifier = (widget === undefined || widget === 1) ? '' : widget;
|
||||
scope[iterator + 'SearchField' + modifier] = '';
|
||||
scope[iterator + 'SearchFieldLabel' + modifier] = '';
|
||||
for (fld in list.fields) {
|
||||
if (list.fields[fld].searchWidget === undefined && widget === 1 ||
|
||||
list.fields[fld].searchWidget === widget) {
|
||||
if (list.fields[fld].key) {
|
||||
if (list.fields[fld].sourceModel) {
|
||||
fka = list.fields[fld].sourceModel + '__' + list.fields[fld].sourceField;
|
||||
sort_order = (list.fields[fld].desc) ? '-' + fka : fka;
|
||||
} else {
|
||||
sort_order = (list.fields[fld].desc) ? '-' + fld : fld;
|
||||
}
|
||||
if (list.fields[fld].searchable === undefined || list.fields[fld].searchable === true) {
|
||||
scope[iterator + 'SearchField' + modifier] = fld;
|
||||
scope[iterator + 'SearchFieldLabel' + modifier] = list.fields[fld].label;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Empty(scope[iterator + 'SearchField' + modifier])) {
|
||||
// A field marked as key may not be 'searchable'. Find the first searchable field.
|
||||
for (fld in list.fields) {
|
||||
if (list.fields[fld].searchWidget === undefined && widget === 1 ||
|
||||
list.fields[fld].searchWidget === widget) {
|
||||
if (list.fields[fld].searchable === undefined || list.fields[fld].searchable === true) {
|
||||
scope[iterator + 'SearchField' + modifier] = fld;
|
||||
scope[iterator + 'SearchFieldLabel' + modifier] = list.fields[fld].label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope[iterator + 'SearchType' + modifier] = 'icontains';
|
||||
scope[iterator + 'SearchTypeLabel' + modifier] = 'Contains';
|
||||
scope[iterator + 'SearchParams' + modifier] = '';
|
||||
scope[iterator + 'SearchValue' + modifier] = '';
|
||||
scope[iterator + 'SelectShow' + modifier] = false; // show/hide the Select
|
||||
scope[iterator + 'HideSearchType' + modifier] = false;
|
||||
scope[iterator + 'InputDisable' + modifier] = false;
|
||||
scope[iterator + 'ExtraParms' + modifier] = '';
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = true;
|
||||
scope[iterator + 'HideAllStartBtn' + modifier] = false;
|
||||
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder) {
|
||||
if (scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder]) {
|
||||
// if set to a scope variable
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder];
|
||||
} else {
|
||||
// Set to a string value in the list definition
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder;
|
||||
}
|
||||
} else {
|
||||
// Default value
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = 'Search';
|
||||
}
|
||||
|
||||
scope[iterator + 'InputDisable' + modifier] =
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchObject === 'all') ? true : false;
|
||||
|
||||
f = scope[iterator + 'SearchField' + modifier];
|
||||
if (list.fields[f]) {
|
||||
if (list.fields[f].searchType && (list.fields[f].searchType === 'boolean' ||
|
||||
list.fields[f].searchType === 'select')) {
|
||||
scope[iterator + 'SelectShow' + modifier] = true;
|
||||
scope[iterator + 'SearchSelectOpts' + modifier] = list.fields[f].searchOptions;
|
||||
}
|
||||
if (list.fields[f].searchType && list.fields[f].searchType === 'int') {
|
||||
scope[iterator + 'HideSearchType' + modifier] = true;
|
||||
}
|
||||
if (list.fields[f].searchType && list.fields[f].searchType === 'gtzero') {
|
||||
scope[iterator + 'InputHide' + modifier] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (setWidgets) {
|
||||
// Set default values for each search widget on the page
|
||||
widgets = (list.searchWidgets) ? list.searchWidgets : 1;
|
||||
for (i = 1; i <= widgets; i++) {
|
||||
modifier = (i === 1) ? '' : i;
|
||||
if ($('#search-widget-container' + modifier)) {
|
||||
setDefaults(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
current_params = {
|
||||
set: set,
|
||||
defaultUrl: defaultUrl,
|
||||
@ -38,471 +134,351 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
|
||||
iterator: iterator,
|
||||
sort_order: sort_order
|
||||
};
|
||||
|
||||
Store('CurrentSearchParams', current_params); // Save in case Activity Stream widget needs to restore */
|
||||
|
||||
function setDefaults(widget) {
|
||||
// Set default values
|
||||
var f, fld, fka, modifier;
|
||||
modifier = (widget === undefined || widget === 1) ? '' : widget;
|
||||
scope[iterator + 'SearchField' + modifier] = '';
|
||||
scope[iterator + 'SearchFieldLabel' + modifier] = '';
|
||||
for (fld in list.fields) {
|
||||
if (list.fields[fld].searchWidget === undefined && widget === 1 ||
|
||||
list.fields[fld].searchWidget === widget) {
|
||||
if (list.fields[fld].key) {
|
||||
if (list.fields[fld].sourceModel) {
|
||||
fka = list.fields[fld].sourceModel + '__' + list.fields[fld].sourceField;
|
||||
sort_order = (list.fields[fld].desc) ? '-' + fka : fka;
|
||||
}
|
||||
else {
|
||||
sort_order = (list.fields[fld].desc) ? '-' + fld : fld;
|
||||
}
|
||||
if (list.fields[fld].searchable === undefined || list.fields[fld].searchable === true) {
|
||||
scope[iterator + 'SearchField' + modifier] = fld;
|
||||
scope[iterator + 'SearchFieldLabel' + modifier] = list.fields[fld].label;
|
||||
}
|
||||
break;
|
||||
Store('CurrentSearchParams', current_params); // Save in case Activity Stream widget needs to restore
|
||||
|
||||
|
||||
// Functions to handle search widget changes
|
||||
scope.setSearchField = function (iterator, fld, label, widget) {
|
||||
|
||||
var modifier = (widget === undefined || widget === 1) ? '' : widget;
|
||||
scope[iterator + 'SearchFieldLabel' + modifier] = label;
|
||||
scope[iterator + 'SearchField' + modifier] = fld;
|
||||
scope[iterator + 'SearchValue' + modifier] = '';
|
||||
scope[iterator + 'SelectShow' + modifier] = false;
|
||||
scope[iterator + 'HideSearchType' + modifier] = false;
|
||||
scope[iterator + 'InputHide' + modifier] = false;
|
||||
scope[iterator + 'SearchType' + modifier] = 'icontains';
|
||||
scope[iterator + 'InputDisable' + modifier] = (list.fields[fld].searchObject === 'all') ? true : false;
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = true;
|
||||
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder) {
|
||||
if (scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder]) {
|
||||
// if set to a scope variable
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = scope[list.fields[scope[iterator + 'SearchField' +
|
||||
modifier]].searchPlaceholder];
|
||||
} else {
|
||||
// Set to a string value in the list definition
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = list.fields[scope[iterator + 'SearchField' +
|
||||
modifier]].searchPlaceholder;
|
||||
}
|
||||
} else {
|
||||
// Default value
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = 'Search';
|
||||
}
|
||||
}
|
||||
|
||||
if (Empty(scope[iterator + 'SearchField' + modifier])) {
|
||||
// A field marked as key may not be 'searchable'. Find the first searchable field.
|
||||
for (fld in list.fields) {
|
||||
if (list.fields[fld].searchWidget === undefined && widget === 1 ||
|
||||
list.fields[fld].searchWidget === widget) {
|
||||
if (list.fields[fld].searchable === undefined || list.fields[fld].searchable === true) {
|
||||
scope[iterator + 'SearchField' + modifier] = fld;
|
||||
scope[iterator + 'SearchFieldLabel' + modifier] = list.fields[fld].label;
|
||||
break;
|
||||
}
|
||||
if (list.fields[fld].searchType && list.fields[fld].searchType === 'gtzero') {
|
||||
scope[iterator + "InputDisable" + modifier] = true;
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = false;
|
||||
scope.search(iterator);
|
||||
} else if (list.fields[fld].searchSingleValue) {
|
||||
// Query a specific attribute for one specific value
|
||||
// searchSingleValue: true
|
||||
// searchType: 'boolean|int|etc.'
|
||||
// searchValue: < value to match for boolean use 'true'|'false' >
|
||||
scope[iterator + 'InputDisable' + modifier] = true;
|
||||
scope[iterator + "SearchValue" + modifier] = list.fields[fld].searchValue;
|
||||
// For boolean type, SearchValue must be an object
|
||||
if (list.fields[fld].searchType === 'boolean' && list.fields[fld].searchValue === 'true') {
|
||||
scope[iterator + "SearchSelectValue" + modifier] = {
|
||||
value: 1
|
||||
};
|
||||
} else if (list.fields[fld].searchType === 'boolean' && list.fields[fld].searchValue === 'false') {
|
||||
scope[iterator + "SearchSelectValue" + modifier] = {
|
||||
value: 0
|
||||
};
|
||||
} else {
|
||||
scope[iterator + "SearchSelectValue" + modifier] = {
|
||||
value: list.fields[fld].searchValue
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope[iterator + 'SearchType' + modifier] = 'icontains';
|
||||
scope[iterator + 'SearchTypeLabel' + modifier] = 'Contains';
|
||||
scope[iterator + 'SearchParams' + modifier] = '';
|
||||
scope[iterator + 'SearchValue' + modifier] = '';
|
||||
scope[iterator + 'SelectShow' + modifier] = false; // show/hide the Select
|
||||
scope[iterator + 'HideSearchType' + modifier] = false;
|
||||
scope[iterator + 'InputDisable' + modifier] = false;
|
||||
scope[iterator + 'ExtraParms' + modifier] = '';
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = true;
|
||||
scope[iterator + 'HideAllStartBtn' + modifier] = false;
|
||||
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder) {
|
||||
if (scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder]) {
|
||||
// if set to a scope variable
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder];
|
||||
}
|
||||
else {
|
||||
// Set to a string value in the list definition
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Default value
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = 'Search';
|
||||
}
|
||||
|
||||
scope[iterator + 'InputDisable' + modifier] =
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchObject === 'all') ? true : false;
|
||||
|
||||
f = scope[iterator + 'SearchField' + modifier];
|
||||
if (list.fields[f]) {
|
||||
if ( list.fields[f].searchType && (list.fields[f].searchType === 'boolean' ||
|
||||
list.fields[f].searchType === 'select') ) {
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = false;
|
||||
} else if (list.fields[fld].searchType === 'in') {
|
||||
scope[iterator + "SearchType" + modifier] = 'in';
|
||||
scope[iterator + "SearchValue" + modifier] = list.fields[fld].searchValue;
|
||||
scope[iterator + "InputDisable" + modifier] = true;
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = false;
|
||||
} else if (list.fields[fld].searchType && (list.fields[fld].searchType === 'boolean' ||
|
||||
list.fields[fld].searchType === 'select' || list.fields[fld].searchType === 'select_or')) {
|
||||
scope[iterator + 'SelectShow' + modifier] = true;
|
||||
scope[iterator + 'SearchSelectOpts' + modifier] = list.fields[f].searchOptions;
|
||||
scope[iterator + 'SearchSelectOpts' + modifier] = list.fields[fld].searchOptions;
|
||||
} else if (list.fields[fld].searchType && list.fields[fld].searchType === 'int') {
|
||||
//scope[iterator + 'HideSearchType' + modifier] = true;
|
||||
scope[iterator + 'SearchType' + modifier] = 'int';
|
||||
} else if (list.fields[fld].searchType && list.fields[fld].searchType === 'isnull') {
|
||||
scope[iterator + 'SearchType' + modifier] = 'isnull';
|
||||
scope[iterator + 'InputDisable' + modifier] = true;
|
||||
scope[iterator + 'SearchValue' + modifier] = 'true';
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = false;
|
||||
}
|
||||
if (list.fields[f].searchType && list.fields[f].searchType === 'int') {
|
||||
scope[iterator + 'HideSearchType' + modifier] = true;
|
||||
}
|
||||
if (list.fields[f].searchType && list.fields[f].searchType === 'gtzero') {
|
||||
scope[iterator + 'InputHide' + modifier] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (setWidgets) {
|
||||
// Set default values for each search widget on the page
|
||||
widgets = (list.searchWidgets) ? list.searchWidgets : 1;
|
||||
for (i=1; i <= widgets; i++) {
|
||||
modifier = (i === 1) ? '' : i;
|
||||
if ( $('#search-widget-container' + modifier) ) {
|
||||
|
||||
scope.search(iterator);
|
||||
|
||||
};
|
||||
|
||||
scope.resetSearch = function (iterator) {
|
||||
// Respdond to click of reset button
|
||||
var i,
|
||||
widgets = (list.searchWidgets) ? list.searchWidgets : 1;
|
||||
|
||||
for (i = 1; i <= widgets; i++) {
|
||||
// Clear each search widget
|
||||
setDefaults(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
current_params = {
|
||||
set: set,
|
||||
defaultUrl: defaultUrl,
|
||||
list: list,
|
||||
iterator: iterator,
|
||||
sort_order: sort_order
|
||||
};
|
||||
|
||||
Store('CurrentSearchParams', current_params); // Save in case Activity Stream widget needs to restore
|
||||
|
||||
|
||||
// Functions to handle search widget changes
|
||||
scope.setSearchField = function(iterator, fld, label, widget) {
|
||||
|
||||
var modifier = (widget === undefined || widget === 1) ? '' : widget;
|
||||
scope[iterator + 'SearchFieldLabel' + modifier] = label;
|
||||
scope[iterator + 'SearchField' + modifier] = fld;
|
||||
scope[iterator + 'SearchValue' + modifier] = '';
|
||||
scope[iterator + 'SelectShow' + modifier] = false;
|
||||
scope[iterator + 'HideSearchType' + modifier] = false;
|
||||
scope[iterator + 'InputHide' + modifier] = false;
|
||||
scope[iterator + 'SearchType' + modifier] = 'icontains';
|
||||
scope[iterator + 'InputDisable' + modifier] = (list.fields[fld].searchObject === 'all') ? true : false;
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = true;
|
||||
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder) {
|
||||
if (scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder]) {
|
||||
// if set to a scope variable
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = scope[list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder];
|
||||
}
|
||||
else {
|
||||
// Set to a string value in the list definition
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = list.fields[scope[iterator + 'SearchField' + modifier]].searchPlaceholder;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Default value
|
||||
scope[iterator + 'SearchPlaceholder' + modifier] = 'Search';
|
||||
}
|
||||
|
||||
if (list.fields[fld].searchType && list.fields[fld].searchType === 'gtzero') {
|
||||
scope[iterator + "InputDisable" + modifier] = true;
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = false;
|
||||
// Force removal of search keys from the URL
|
||||
window.location = '/#' + $location.path();
|
||||
scope.search(iterator);
|
||||
}
|
||||
else if (list.fields[fld].searchSingleValue){
|
||||
// Query a specific attribute for one specific value
|
||||
// searchSingleValue: true
|
||||
// searchType: 'boolean|int|etc.'
|
||||
// searchValue: < value to match for boolean use 'true'|'false' >
|
||||
scope[iterator + 'InputDisable' + modifier] = true;
|
||||
scope[iterator + "SearchValue" + modifier] = list.fields[fld].searchValue;
|
||||
// For boolean type, SearchValue must be an object
|
||||
if (list.fields[fld].searchType === 'boolean' && list.fields[fld].searchValue === 'true') {
|
||||
scope[iterator + "SearchSelectValue" + modifier] = { value: 1 };
|
||||
}
|
||||
else if (list.fields[fld].searchType === 'boolean' && list.fields[fld].searchValue === 'false') {
|
||||
scope[iterator + "SearchSelectValue" + modifier] = { value: 0 };
|
||||
}
|
||||
else {
|
||||
scope[iterator + "SearchSelectValue" + modifier] = { value: list.fields[fld].searchValue };
|
||||
}
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = false;
|
||||
}
|
||||
else if (list.fields[fld].searchType === 'in') {
|
||||
scope[iterator + "SearchType" + modifier] = 'in';
|
||||
scope[iterator + "SearchValue" + modifier] = list.fields[fld].searchValue;
|
||||
scope[iterator + "InputDisable" + modifier] = true;
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = false;
|
||||
}
|
||||
else if (list.fields[fld].searchType && (list.fields[fld].searchType === 'boolean' ||
|
||||
list.fields[fld].searchType === 'select' || list.fields[fld].searchType === 'select_or')) {
|
||||
scope[iterator + 'SelectShow' + modifier] = true;
|
||||
scope[iterator + 'SearchSelectOpts' + modifier] = list.fields[fld].searchOptions;
|
||||
}
|
||||
else if (list.fields[fld].searchType && list.fields[fld].searchType === 'int') {
|
||||
//scope[iterator + 'HideSearchType' + modifier] = true;
|
||||
scope[iterator + 'SearchType' + modifier] = 'int';
|
||||
}
|
||||
else if (list.fields[fld].searchType && list.fields[fld].searchType === 'isnull') {
|
||||
scope[iterator + 'SearchType' + modifier] = 'isnull';
|
||||
scope[iterator + 'InputDisable' + modifier] = true;
|
||||
scope[iterator + 'SearchValue' + modifier] = 'true';
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = false;
|
||||
}
|
||||
|
||||
scope.search(iterator);
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
scope.resetSearch = function(iterator) {
|
||||
// Respdond to click of reset button
|
||||
var i,
|
||||
widgets = (list.searchWidgets) ? list.searchWidgets : 1;
|
||||
|
||||
for (i=1; i <= widgets; i++) {
|
||||
// Clear each search widget
|
||||
setDefaults(i);
|
||||
if (scope.removeDoSearch) {
|
||||
scope.removeDoSearch();
|
||||
}
|
||||
// Force removal of search keys from the URL
|
||||
window.location = '/#' + $location.path();
|
||||
scope.search(iterator);
|
||||
};
|
||||
|
||||
if (scope.removeDoSearch) {
|
||||
scope.removeDoSearch();
|
||||
}
|
||||
scope.removeDoSearch = scope.$on('doSearch', function(e, iterator, page, load) {
|
||||
//
|
||||
// Execute the search
|
||||
//
|
||||
scope[iterator + 'Loading'] = (load === undefined || load === true) ? true : false;
|
||||
var url = defaultUrl, connect;
|
||||
scope.removeDoSearch = scope.$on('doSearch', function (e, iterator, page, load) {
|
||||
//
|
||||
// Execute the search
|
||||
//
|
||||
scope[iterator + 'Loading'] = (load === undefined || load === true) ? true : false;
|
||||
var url = defaultUrl,
|
||||
connect;
|
||||
|
||||
//finalize and execute the query
|
||||
scope[iterator + 'Page'] = (page) ? parseInt(page) - 1 : 0;
|
||||
if (scope[iterator + 'SearchParams']) {
|
||||
if (/\/$/.test(url)) {
|
||||
url += '?' + scope[iterator + 'SearchParams'];
|
||||
//finalize and execute the query
|
||||
scope[iterator + 'Page'] = (page) ? parseInt(page) - 1 : 0;
|
||||
if (scope[iterator + 'SearchParams']) {
|
||||
if (/\/$/.test(url)) {
|
||||
url += '?' + scope[iterator + 'SearchParams'];
|
||||
} else {
|
||||
url += '&' + scope[iterator + 'SearchParams'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
url += '&' + scope[iterator + 'SearchParams'];
|
||||
}
|
||||
}
|
||||
connect = (/\/$/.test(url)) ? '?' : '&';
|
||||
url += (scope[iterator + '_page_size']) ? connect + 'page_size=' + scope[iterator + '_page_size'] : "";
|
||||
if (page) {
|
||||
connect = (/\/$/.test(url)) ? '?' : '&';
|
||||
url += connect + 'page=' + page;
|
||||
}
|
||||
if (scope[iterator + 'ExtraParms']) {
|
||||
connect = (/\/$/.test(url)) ? '?' : '&';
|
||||
url += connect + scope[iterator + 'ExtraParms'];
|
||||
}
|
||||
url = url.replace(/\&\&/,'&');
|
||||
Refresh({ scope: scope, set: set, iterator: iterator, url: url });
|
||||
});
|
||||
|
||||
|
||||
if (scope.removePrepareSearch) {
|
||||
scope.removePrepareSearch();
|
||||
}
|
||||
scope.removePrepareSearch = scope.$on('prepareSearch', function(e, iterator, page, load, spin) {
|
||||
//
|
||||
// Start building the search key/value pairs. This will process each search widget, if the
|
||||
// selected field is an object type (used on activity stream).
|
||||
//
|
||||
Wait('start');
|
||||
scope[iterator + 'SearchParams'] = '';
|
||||
var i, modifier,
|
||||
widgets = (list.searchWidgets) ? list.searchWidgets : 1;
|
||||
|
||||
for (i=1; i <= widgets; i++) {
|
||||
modifier = (i === 1) ? '' : i;
|
||||
if ( $('#search-widget-container' + modifier) ) {
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchObject) {
|
||||
// Search field of object type
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]].searchObject !== 'all') {
|
||||
// An object type is selected
|
||||
scope[iterator + 'HideAllStartBtn' + modifier] = false;
|
||||
if (scope[iterator + 'SearchValue' + modifier]) {
|
||||
// A search value was entered
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = false;
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]].searchOnID) {
|
||||
scope[iterator + 'SearchParams'] += '&' +
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchObject +
|
||||
'__id=' + scope[iterator + 'SearchValue' + modifier];
|
||||
}
|
||||
else {
|
||||
scope[iterator + 'SearchParams'] += '&' +
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchObject +
|
||||
'__name__icontains=' +
|
||||
scope[iterator + 'SearchValue' + modifier];
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Search value is empty
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = true;
|
||||
scope[iterator + 'SearchParams'] += '&' +
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchField +
|
||||
'=' + list.fields[scope[iterator + 'SearchField' + modifier]].searchObject;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Object Type set to All
|
||||
scope[iterator + 'HideAllStartBtn' + modifier] = true;
|
||||
}
|
||||
}
|
||||
url += (scope[iterator + '_page_size']) ? connect + 'page_size=' + scope[iterator + '_page_size'] : "";
|
||||
if (page) {
|
||||
connect = (/\/$/.test(url)) ? '?' : '&';
|
||||
url += connect + 'page=' + page;
|
||||
}
|
||||
}
|
||||
scope.$emit('prepareSearch2', iterator, page, load, spin);
|
||||
});
|
||||
|
||||
if (scope.removePrepareSearch2) {
|
||||
scope.removePrepareSearch2();
|
||||
}
|
||||
scope.removePrepareSearch2 = scope.$on('prepareSearch2', function(e, iterator, page, load, spin) {
|
||||
// Continue building the search by examining the remaining search widgets. If we're looking at activity_stream,
|
||||
// there's more than one.
|
||||
var i, modifier,
|
||||
widgets = (list.searchWidgets) ? list.searchWidgets : 1;
|
||||
|
||||
for (i=1; i <= widgets; i++) {
|
||||
modifier = (i === 1) ? '' : i;
|
||||
scope[iterator + 'HoldInput' + modifier] = true;
|
||||
if ($('#search-widget-container' + modifier) &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
!list.fields[scope[iterator + 'SearchField' + modifier]].searchObject) {
|
||||
|
||||
// if the search widget exists and its value is not an object, add its parameters to the query
|
||||
|
||||
if (scope[iterator + 'SearchValue' + modifier]) {
|
||||
// if user typed a value in the input box, show the reset link
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = false;
|
||||
}
|
||||
else {
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = true;
|
||||
}
|
||||
|
||||
if ( (!scope[iterator + 'SelectShow' + modifier] && !Empty(scope[iterator + 'SearchValue' + modifier])) ||
|
||||
(scope[iterator + 'SelectShow' + modifier] && scope[iterator + 'SearchSelectValue' + modifier]) ||
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'gtzero') ) {
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]].searchField) {
|
||||
scope[iterator + 'SearchParams'] += '&' + list.fields[scope[iterator + 'SearchField' + modifier]].searchField + '__';
|
||||
}
|
||||
else if (list.fields[scope[iterator + 'SearchField' + modifier]].sourceModel) {
|
||||
// handle fields whose source is a related model e.g. inventories.organization
|
||||
scope[iterator + 'SearchParams'] += '&' + list.fields[scope[iterator + 'SearchField' + modifier]].sourceModel + '__' +
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].sourceField + '__';
|
||||
}
|
||||
else if ( (list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'select') &&
|
||||
(scope[iterator + 'SearchSelectValue' + modifier].value === '' ||
|
||||
scope[iterator + 'SearchSelectValue' + modifier].value === null) ) {
|
||||
scope[iterator + 'SearchParams'] += '&' + scope[iterator + 'SearchField' + modifier] + '__';
|
||||
}
|
||||
else {
|
||||
scope[iterator + 'SearchParams'] += '&' + scope[iterator + 'SearchField' + modifier] + '__';
|
||||
}
|
||||
|
||||
if ( list.fields[scope[iterator + 'SearchField' + modifier]].searchType &&
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'int' ||
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'boolean' ) ) {
|
||||
scope[iterator + 'SearchParams'] += 'int=';
|
||||
}
|
||||
else if ( list.fields[scope[iterator + 'SearchField' + modifier]].searchType &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'gtzero' ) {
|
||||
scope[iterator + 'SearchParams'] += 'gt=0';
|
||||
}
|
||||
else if ( (list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'select') &&
|
||||
(scope[iterator + 'SearchSelectValue' + modifier].value === '' ||
|
||||
scope[iterator + 'SearchSelectValue' + modifier].value === null) ) {
|
||||
scope[iterator + 'SearchParams'] += 'iexact=';
|
||||
}
|
||||
else {
|
||||
scope[iterator + 'SearchParams'] += scope[iterator + 'SearchType' + modifier] + '=';
|
||||
}
|
||||
|
||||
if ( list.fields[scope[iterator + 'SearchField' + modifier]].searchType &&
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'boolean' ||
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'select') ) {
|
||||
scope[iterator + 'SearchParams'] += scope[iterator + 'SearchSelectValue' + modifier].value;
|
||||
}
|
||||
else {
|
||||
if ( (!list.fields[scope[iterator + 'SearchField' + modifier]].searchType) ||
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]].searchType &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType !== 'or' &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType !== 'gtzero') ) {
|
||||
scope[iterator + 'SearchParams'] += encodeURI(scope[iterator + 'SearchValue' + modifier]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( (iterator === 'inventory' && scope.inventoryFailureFilter) ||
|
||||
(iterator === 'host' && scope.hostFailureFilter) ) {
|
||||
//Things that bypass the search widget. Should go back and add a second widget possibly on
|
||||
//inventory pages and eliminate this
|
||||
scope[iterator + 'SearchParams'] += '&has_active_failures=true';
|
||||
}
|
||||
|
||||
if (sort_order) {
|
||||
scope[iterator + 'SearchParams'] += (scope[iterator + 'SearchParams']) ? '&' : '';
|
||||
scope[iterator + 'SearchParams'] += 'order_by=' + encodeURI(sort_order);
|
||||
}
|
||||
|
||||
scope.$emit('doSearch', iterator, page, load, spin);
|
||||
});
|
||||
|
||||
scope.startSearch = function(e,iterator) {
|
||||
// If use clicks enter while on input field, start the search
|
||||
if (e.keyCode === 13) {
|
||||
scope.search(iterator);
|
||||
}
|
||||
};
|
||||
|
||||
scope.search = function(iterator, page, load) {
|
||||
// Called to initiate a searh.
|
||||
// Page is optional. Added to accomodate back function on Job Events detail.
|
||||
// Spin optional -set to false if spin not desired.
|
||||
// Load optional -set to false if loading message not desired
|
||||
load = (load === undefined) ? true : false;
|
||||
if (load) {
|
||||
scope[set] = [];
|
||||
}
|
||||
scope.$emit('prepareSearch', iterator, page, load);
|
||||
};
|
||||
|
||||
|
||||
scope.sort = function(fld) {
|
||||
// reset sort icons back to 'icon-sort' on all columns
|
||||
// except the one clicked
|
||||
$('.list-header').each(function() {
|
||||
if ($(this).attr('id') !== fld + '-header') {
|
||||
var icon = $(this).find('i');
|
||||
icon.attr('class','fa fa-sort');
|
||||
if (scope[iterator + 'ExtraParms']) {
|
||||
connect = (/\/$/.test(url)) ? '?' : '&';
|
||||
url += connect + scope[iterator + 'ExtraParms'];
|
||||
}
|
||||
url = url.replace(/\&\&/, '&');
|
||||
Refresh({
|
||||
scope: scope,
|
||||
set: set,
|
||||
iterator: iterator,
|
||||
url: url
|
||||
});
|
||||
});
|
||||
|
||||
// Toggle the icon for the clicked column
|
||||
// and set the sort direction
|
||||
var icon = $('#' + fld + '-header i'),
|
||||
direction = '';
|
||||
if (icon.hasClass('fa-sort')) {
|
||||
icon.removeClass('fa-sort');
|
||||
icon.addClass('fa-sort-up');
|
||||
}
|
||||
else if (icon.hasClass('fa-sort-up')) {
|
||||
icon.removeClass('fa-sort-up');
|
||||
icon.addClass('fa-sort-down');
|
||||
direction = '-';
|
||||
}
|
||||
else if (icon.hasClass('fa-sort-down')) {
|
||||
icon.removeClass('fa-sort-down');
|
||||
icon.addClass('fa-sort-up');
|
||||
}
|
||||
|
||||
// Set the sorder order value and call the API to refresh the list with the new order
|
||||
if (list.fields[fld].searchField) {
|
||||
sort_order = direction + list.fields[fld].searchField;
|
||||
|
||||
if (scope.removePrepareSearch) {
|
||||
scope.removePrepareSearch();
|
||||
}
|
||||
else if (list.fields[fld].sortField) {
|
||||
sort_order = direction + list.fields[fld].sortField;
|
||||
}
|
||||
else {
|
||||
if (list.fields[fld].sourceModel) {
|
||||
sort_order = direction + list.fields[fld].sourceModel + '__' + list.fields[fld].sourceField;
|
||||
}
|
||||
else {
|
||||
sort_order = direction + fld;
|
||||
scope.removePrepareSearch = scope.$on('prepareSearch', function (e, iterator, page, load, spin) {
|
||||
//
|
||||
// Start building the search key/value pairs. This will process each search widget, if the
|
||||
// selected field is an object type (used on activity stream).
|
||||
//
|
||||
Wait('start');
|
||||
scope[iterator + 'SearchParams'] = '';
|
||||
var i, modifier,
|
||||
widgets = (list.searchWidgets) ? list.searchWidgets : 1;
|
||||
|
||||
for (i = 1; i <= widgets; i++) {
|
||||
modifier = (i === 1) ? '' : i;
|
||||
if ($('#search-widget-container' + modifier)) {
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchObject) {
|
||||
// Search field of object type
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]].searchObject !== 'all') {
|
||||
// An object type is selected
|
||||
scope[iterator + 'HideAllStartBtn' + modifier] = false;
|
||||
if (scope[iterator + 'SearchValue' + modifier]) {
|
||||
// A search value was entered
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = false;
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]].searchOnID) {
|
||||
scope[iterator + 'SearchParams'] += '&' +
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchObject +
|
||||
'__id=' + scope[iterator + 'SearchValue' + modifier];
|
||||
} else {
|
||||
scope[iterator + 'SearchParams'] += '&' +
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchObject +
|
||||
'__name__icontains=' +
|
||||
scope[iterator + 'SearchValue' + modifier];
|
||||
}
|
||||
} else {
|
||||
// Search value is empty
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = true;
|
||||
scope[iterator + 'SearchParams'] += '&' +
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchField +
|
||||
'=' + list.fields[scope[iterator + 'SearchField' + modifier]].searchObject;
|
||||
}
|
||||
} else {
|
||||
// Object Type set to All
|
||||
scope[iterator + 'HideAllStartBtn' + modifier] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scope.$emit('prepareSearch2', iterator, page, load, spin);
|
||||
});
|
||||
|
||||
if (scope.removePrepareSearch2) {
|
||||
scope.removePrepareSearch2();
|
||||
}
|
||||
scope.search(list.iterator);
|
||||
};
|
||||
scope.removePrepareSearch2 = scope.$on('prepareSearch2', function (e, iterator, page, load, spin) {
|
||||
// Continue building the search by examining the remaining search widgets. If we're looking at activity_stream,
|
||||
// there's more than one.
|
||||
var i, modifier,
|
||||
widgets = (list.searchWidgets) ? list.searchWidgets : 1;
|
||||
|
||||
// Call after modal dialogs to remove any lingering callbacks
|
||||
scope.searchCleanup = function() {
|
||||
scope.removeDoSearch();
|
||||
scope.removePrepareSearch();
|
||||
scope.removePrepareSearch2();
|
||||
};
|
||||
for (i = 1; i <= widgets; i++) {
|
||||
modifier = (i === 1) ? '' : i;
|
||||
scope[iterator + 'HoldInput' + modifier] = true;
|
||||
if ($('#search-widget-container' + modifier) &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]] && !list.fields[scope[iterator + 'SearchField' + modifier]].searchObject) {
|
||||
|
||||
};
|
||||
}]);
|
||||
// if the search widget exists and its value is not an object, add its parameters to the query
|
||||
|
||||
if (scope[iterator + 'SearchValue' + modifier]) {
|
||||
// if user typed a value in the input box, show the reset link
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = false;
|
||||
} else {
|
||||
scope[iterator + 'ShowStartBtn' + modifier] = true;
|
||||
}
|
||||
|
||||
if ((!scope[iterator + 'SelectShow' + modifier] && !Empty(scope[iterator + 'SearchValue' + modifier])) ||
|
||||
(scope[iterator + 'SelectShow' + modifier] && scope[iterator + 'SearchSelectValue' + modifier]) ||
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]] &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'gtzero')) {
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]].searchField) {
|
||||
scope[iterator + 'SearchParams'] += '&' + list.fields[scope[iterator + 'SearchField' + modifier]].searchField + '__';
|
||||
} else if (list.fields[scope[iterator + 'SearchField' + modifier]].sourceModel) {
|
||||
// handle fields whose source is a related model e.g. inventories.organization
|
||||
scope[iterator + 'SearchParams'] += '&' + list.fields[scope[iterator + 'SearchField' + modifier]].sourceModel + '__' +
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].sourceField + '__';
|
||||
} else if ((list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'select') &&
|
||||
(scope[iterator + 'SearchSelectValue' + modifier].value === '' ||
|
||||
scope[iterator + 'SearchSelectValue' + modifier].value === null)) {
|
||||
scope[iterator + 'SearchParams'] += '&' + scope[iterator + 'SearchField' + modifier] + '__';
|
||||
} else {
|
||||
scope[iterator + 'SearchParams'] += '&' + scope[iterator + 'SearchField' + modifier] + '__';
|
||||
}
|
||||
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]].searchType &&
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'int' ||
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'boolean')) {
|
||||
scope[iterator + 'SearchParams'] += 'int=';
|
||||
} else if (list.fields[scope[iterator + 'SearchField' + modifier]].searchType &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'gtzero') {
|
||||
scope[iterator + 'SearchParams'] += 'gt=0';
|
||||
} else if ((list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'select') &&
|
||||
(scope[iterator + 'SearchSelectValue' + modifier].value === '' ||
|
||||
scope[iterator + 'SearchSelectValue' + modifier].value === null)) {
|
||||
scope[iterator + 'SearchParams'] += 'iexact=';
|
||||
} else {
|
||||
scope[iterator + 'SearchParams'] += scope[iterator + 'SearchType' + modifier] + '=';
|
||||
}
|
||||
|
||||
if (list.fields[scope[iterator + 'SearchField' + modifier]].searchType &&
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'boolean' ||
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType === 'select')) {
|
||||
scope[iterator + 'SearchParams'] += scope[iterator + 'SearchSelectValue' + modifier].value;
|
||||
} else {
|
||||
if ((!list.fields[scope[iterator + 'SearchField' + modifier]].searchType) ||
|
||||
(list.fields[scope[iterator + 'SearchField' + modifier]].searchType &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType !== 'or' &&
|
||||
list.fields[scope[iterator + 'SearchField' + modifier]].searchType !== 'gtzero')) {
|
||||
scope[iterator + 'SearchParams'] += encodeURI(scope[iterator + 'SearchValue' + modifier]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((iterator === 'inventory' && scope.inventoryFailureFilter) ||
|
||||
(iterator === 'host' && scope.hostFailureFilter)) {
|
||||
//Things that bypass the search widget. Should go back and add a second widget possibly on
|
||||
//inventory pages and eliminate this
|
||||
scope[iterator + 'SearchParams'] += '&has_active_failures=true';
|
||||
}
|
||||
|
||||
if (sort_order) {
|
||||
scope[iterator + 'SearchParams'] += (scope[iterator + 'SearchParams']) ? '&' : '';
|
||||
scope[iterator + 'SearchParams'] += 'order_by=' + encodeURI(sort_order);
|
||||
}
|
||||
|
||||
scope.$emit('doSearch', iterator, page, load, spin);
|
||||
});
|
||||
|
||||
scope.startSearch = function (e, iterator) {
|
||||
// If use clicks enter while on input field, start the search
|
||||
if (e.keyCode === 13) {
|
||||
scope.search(iterator);
|
||||
}
|
||||
};
|
||||
|
||||
scope.search = function (iterator, page, load) {
|
||||
// Called to initiate a searh.
|
||||
// Page is optional. Added to accomodate back function on Job Events detail.
|
||||
// Spin optional -set to false if spin not desired.
|
||||
// Load optional -set to false if loading message not desired
|
||||
load = (load === undefined) ? true : false;
|
||||
if (load) {
|
||||
scope[set] = [];
|
||||
}
|
||||
scope.$emit('prepareSearch', iterator, page, load);
|
||||
};
|
||||
|
||||
|
||||
scope.sort = function (fld) {
|
||||
// reset sort icons back to 'icon-sort' on all columns
|
||||
// except the one clicked
|
||||
$('.list-header').each(function () {
|
||||
if ($(this).attr('id') !== fld + '-header') {
|
||||
var icon = $(this).find('i');
|
||||
icon.attr('class', 'fa fa-sort');
|
||||
}
|
||||
});
|
||||
|
||||
// Toggle the icon for the clicked column
|
||||
// and set the sort direction
|
||||
var icon = $('#' + fld + '-header i'),
|
||||
direction = '';
|
||||
if (icon.hasClass('fa-sort')) {
|
||||
icon.removeClass('fa-sort');
|
||||
icon.addClass('fa-sort-up');
|
||||
} else if (icon.hasClass('fa-sort-up')) {
|
||||
icon.removeClass('fa-sort-up');
|
||||
icon.addClass('fa-sort-down');
|
||||
direction = '-';
|
||||
} else if (icon.hasClass('fa-sort-down')) {
|
||||
icon.removeClass('fa-sort-down');
|
||||
icon.addClass('fa-sort-up');
|
||||
}
|
||||
|
||||
// Set the sorder order value and call the API to refresh the list with the new order
|
||||
if (list.fields[fld].searchField) {
|
||||
sort_order = direction + list.fields[fld].searchField;
|
||||
} else if (list.fields[fld].sortField) {
|
||||
sort_order = direction + list.fields[fld].sortField;
|
||||
} else {
|
||||
if (list.fields[fld].sourceModel) {
|
||||
sort_order = direction + list.fields[fld].sourceModel + '__' + list.fields[fld].sourceField;
|
||||
} else {
|
||||
sort_order = direction + fld;
|
||||
}
|
||||
}
|
||||
scope.search(list.iterator);
|
||||
};
|
||||
|
||||
// Call after modal dialogs to remove any lingering callbacks
|
||||
scope.searchCleanup = function () {
|
||||
scope.removeDoSearch();
|
||||
scope.removePrepareSearch();
|
||||
scope.removePrepareSearch2();
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -2,106 +2,126 @@
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* TeamHelper
|
||||
* Routines shared amongst the team controllers
|
||||
* Routines shared amongst the team controllers
|
||||
*/
|
||||
|
||||
angular.module('TeamHelper', [ 'RestServices', 'Utilities', 'OrganizationListDefinition',
|
||||
'SearchHelper', 'PaginationHelpers', 'ListGenerator' ])
|
||||
.factory('SetTeamListeners', ['Alert', 'Rest', function(Alert, Rest) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var set = params.set;
|
||||
var iterator = params.iterator;
|
||||
|
||||
// Listeners to perform lookups after main inventory list loads
|
||||
'use strict';
|
||||
|
||||
scope.$on('TeamResultFound', function(e, results, lookup_results) {
|
||||
if ( lookup_results.length == results.length ) {
|
||||
key = 'organization';
|
||||
property = 'organization_name';
|
||||
for (var i=0; i < results.length; i++) {
|
||||
for (var j=0; j < lookup_results.length; j++) {
|
||||
if (results[i][key] == lookup_results[j].id) {
|
||||
results[i][property] = lookup_results[j].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
scope[iterator + 'SearchSpin'] = false;
|
||||
scope[set] = results;
|
||||
}
|
||||
});
|
||||
angular.module('TeamHelper', ['RestServices', 'Utilities', 'OrganizationListDefinition', 'SearchHelper',
|
||||
'PaginationHelpers', 'ListGenerator'
|
||||
])
|
||||
.factory('SetTeamListeners', ['Alert', 'Rest',
|
||||
function (Alert, Rest) {
|
||||
return function (params) {
|
||||
|
||||
scope.$on('TeamRefreshFinished', function(e, results) {
|
||||
// Loop through the result set (sent to us by the search helper) and
|
||||
// lookup the id and name of each organization. After each lookup
|
||||
// completes, call resultFound.
|
||||
|
||||
var lookup_results = [];
|
||||
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
Rest.setUrl('/api/v1/organizations/' + results[i].organization + '/');
|
||||
Rest.get()
|
||||
.success( function( data, status, headers, config) {
|
||||
lookup_results.push({ id: data.id, value: data.name });
|
||||
scope.$emit('TeamResultFound', results, lookup_results);
|
||||
})
|
||||
.error( function( data, status, headers, config) {
|
||||
lookup_results.push({ id: 'error' });
|
||||
scope.$emit('TeamResultFound', results, lookup_results);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('TeamLookUpOrganizationInit', ['Alert', 'Rest', 'OrganizationList', 'GenerateList', 'SearchInit', 'PaginateInit',
|
||||
function(Alert, Rest, OrganizationList, GenerateList, SearchInit, PaginateInit) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var scope = params.scope,
|
||||
set = params.set,
|
||||
iterator = params.iterator;
|
||||
|
||||
// Show pop-up to select organization
|
||||
scope.lookUpOrganization = function() {
|
||||
var list = OrganizationList;
|
||||
var listGenerator = GenerateList;
|
||||
var listScope = listGenerator.inject(list, { mode: 'lookup', hdr: 'Select Organization' });
|
||||
var defaultUrl = '/api/v1/organizations/';
|
||||
// Listeners to perform lookups after main inventory list loads
|
||||
|
||||
listScope.selectAction = function() {
|
||||
var found = false;
|
||||
for (var i=0; i < listScope[list.name].length; i++) {
|
||||
if (listScope[list.iterator + "_" + listScope[list.name][i].id + "_class"] == "success") {
|
||||
found = true;
|
||||
scope['organization'] = listScope[list.name][i].id;
|
||||
scope['organization_name'] = listScope[list.name][i].name;
|
||||
scope['team_form'].$setDirty();
|
||||
listGenerator.hide();
|
||||
scope.$on('TeamResultFound', function (e, results, lookup_results) {
|
||||
var i, j, key, property;
|
||||
if (lookup_results.length === results.length) {
|
||||
key = 'organization';
|
||||
property = 'organization_name';
|
||||
for (i = 0; i < results.length; i++) {
|
||||
for (j = 0; j < lookup_results.length; j++) {
|
||||
if (results[i][key] === lookup_results[j].id) {
|
||||
results[i][property] = lookup_results[j].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
scope[iterator + 'SearchSpin'] = false;
|
||||
scope[set] = results;
|
||||
}
|
||||
}
|
||||
if (found == false) {
|
||||
Alert('No Selection', 'Click on a row to select an Organization before clicking the Select button.');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
listScope.toggle_organization = function(id) {
|
||||
// when user clicks a row, remove 'success' class from all rows except clicked-on row
|
||||
if (listScope[list.name]) {
|
||||
for (var i=0; i < listScope[list.name].length; i++) {
|
||||
listScope[list.iterator + "_" + listScope[list.name][i].id + "_class"] = "";
|
||||
}
|
||||
}
|
||||
if (id != null && id != undefined) {
|
||||
listScope[list.iterator + "_" + id + "_class"] = "success";
|
||||
}
|
||||
}
|
||||
scope.$on('TeamRefreshFinished', function (e, results) {
|
||||
// Loop through the result set (sent to us by the search helper) and
|
||||
// lookup the id and name of each organization. After each lookup
|
||||
// completes, call resultFound.
|
||||
|
||||
SearchInit({ scope: listScope, set: list.name, list: list, url: defaultUrl });
|
||||
PaginateInit({ scope: listScope, list: list, url: defaultUrl, mode: 'lookup' });
|
||||
scope.search(list.iterator);
|
||||
listScope.toggle_organization(scope.organization);
|
||||
}
|
||||
var i, lookup_results = [], url;
|
||||
|
||||
function getOrganization(url) {
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
lookup_results.push({ id: data.id, value: data.name });
|
||||
scope.$emit('TeamResultFound', results, lookup_results);
|
||||
})
|
||||
.error(function () {
|
||||
lookup_results.push({ id: 'error' });
|
||||
scope.$emit('TeamResultFound', results, lookup_results);
|
||||
});
|
||||
}
|
||||
|
||||
for (i = 0; i < results.length; i++) {
|
||||
url = '/api/v1/organizations/' + results[i].organization + '/';
|
||||
getOrganization(url);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
}]);
|
||||
])
|
||||
|
||||
.factory('TeamLookUpOrganizationInit', ['Alert', 'Rest', 'OrganizationList', 'GenerateList', 'SearchInit', 'PaginateInit',
|
||||
function (Alert, Rest, OrganizationList, GenerateList, SearchInit, PaginateInit) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope;
|
||||
|
||||
// Show pop-up to select organization
|
||||
scope.lookUpOrganization = function () {
|
||||
var list = OrganizationList,
|
||||
listGenerator = GenerateList,
|
||||
listScope = listGenerator.inject(list, { mode: 'lookup', hdr: 'Select Organization' }),
|
||||
defaultUrl = '/api/v1/organizations/';
|
||||
|
||||
listScope.selectAction = function () {
|
||||
var i, found = false;
|
||||
for (i = 0; i < listScope[list.name].length; i++) {
|
||||
if (listScope[list.iterator + "_" + listScope[list.name][i].id + "_class"] === "success") {
|
||||
found = true;
|
||||
scope.organization = listScope[list.name][i].id;
|
||||
scope.organization_name = listScope[list.name][i].name;
|
||||
scope.team_form.$setDirty();
|
||||
listGenerator.hide();
|
||||
}
|
||||
}
|
||||
if (found === false) {
|
||||
Alert('No Selection', 'Click on a row to select an Organization before clicking the Select button.');
|
||||
}
|
||||
};
|
||||
|
||||
listScope.toggle_organization = function (id) {
|
||||
// when user clicks a row, remove 'success' class from all rows except clicked-on row
|
||||
if (listScope[list.name]) {
|
||||
for (var i = 0; i < listScope[list.name].length; i++) {
|
||||
listScope[list.iterator + "_" + listScope[list.name][i].id + "_class"] = "";
|
||||
}
|
||||
}
|
||||
if (id !== null && id !== undefined) {
|
||||
listScope[list.iterator + "_" + id + "_class"] = "success";
|
||||
}
|
||||
};
|
||||
|
||||
SearchInit({
|
||||
scope: listScope,
|
||||
set: list.name,
|
||||
list: list,
|
||||
url: defaultUrl
|
||||
});
|
||||
PaginateInit({
|
||||
scope: listScope,
|
||||
list: list,
|
||||
url: defaultUrl,
|
||||
mode: 'lookup'
|
||||
});
|
||||
scope.search(list.iterator);
|
||||
listScope.toggle_organization(scope.organization);
|
||||
};
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -1,41 +1,41 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* Admins.js
|
||||
* Admins.js
|
||||
* List view object for Admins data model.
|
||||
*
|
||||
* @dict
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('AdminListDefinition', [])
|
||||
.value(
|
||||
'AdminList', {
|
||||
|
||||
.value('AdminList', {
|
||||
|
||||
name: 'admins',
|
||||
iterator: 'admin',
|
||||
selectTitle: 'Add Administrators',
|
||||
editTitle: 'Admins',
|
||||
selectInstructions: '<p>Select existing users by clicking each user or checking the related checkbox. When finished, click the blue ' +
|
||||
'<em>Select</em> button, located bottom right.</p>',
|
||||
'<em>Select</em> button, located bottom right.</p>',
|
||||
base: 'users',
|
||||
index: true,
|
||||
hover: true,
|
||||
|
||||
hover: true,
|
||||
|
||||
fields: {
|
||||
username: {
|
||||
key: true,
|
||||
label: 'Username'
|
||||
},
|
||||
first_name: {
|
||||
},
|
||||
first_name: {
|
||||
label: 'First Name'
|
||||
},
|
||||
last_name: {
|
||||
},
|
||||
last_name: {
|
||||
label: 'Last Name'
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
actions: {},
|
||||
|
||||
fieldActions: {}
|
||||
});
|
||||
@ -1,15 +1,17 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* CloudCredentials.js
|
||||
* CloudCredentials.js
|
||||
* List view object for Credential data model.
|
||||
*
|
||||
* @dict
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('CloudCredentialsListDefinition', [])
|
||||
.value(
|
||||
'CloudCredentialList', {
|
||||
|
||||
.value('CloudCredentialList', {
|
||||
|
||||
name: 'cloudcredentials',
|
||||
iterator: 'cloudcredential',
|
||||
selectTitle: 'Add Cloud Credentials',
|
||||
@ -18,58 +20,58 @@ angular.module('CloudCredentialsListDefinition', [])
|
||||
'<em>Select</em> button, located bottom right.</p> <p>Create a brand new credential by clicking the green <em>Create New</em> button.</p>',
|
||||
index: true,
|
||||
hover: true,
|
||||
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
excludeModal: false
|
||||
},
|
||||
},
|
||||
team: {
|
||||
label: 'Team',
|
||||
ngBind: 'credential.team_name',
|
||||
sourceModel: 'team',
|
||||
sourceField: 'name',
|
||||
excludeModal: true
|
||||
},
|
||||
},
|
||||
user: {
|
||||
label: 'User',
|
||||
ngBind: 'credential.user_username',
|
||||
sourceModel: 'user',
|
||||
sourceField: 'username',
|
||||
excludeModal: true
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
add: {
|
||||
mode: 'all', // One of: edit, select, all
|
||||
mode: 'all', // One of: edit, select, all
|
||||
ngClick: 'addCredential()',
|
||||
"class": 'btn-sm',
|
||||
awToolTip: 'Create a new credential'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
ngClick: "editCredential(\{\{ credential.id \}\})",
|
||||
ngClick: "editCredential(credential.id)",
|
||||
icon: 'fa-edit',
|
||||
label: 'Edit',
|
||||
"class": 'btn-sm',
|
||||
awToolTip: 'Edit credential',
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
},
|
||||
|
||||
"delete": {
|
||||
ngClick: "deleteCredential(\{\{ credential.id \}\},'\{\{ credential.name \}\}')",
|
||||
ngClick: "deleteCredential(credential.id, credential.name)",
|
||||
icon: 'fa-trash-o',
|
||||
label: 'Delete',
|
||||
"class": 'btn-sm',
|
||||
awToolTip: 'Delete credential',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,88 +1,75 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* Credentials.js
|
||||
* Credentials.js
|
||||
* List view object for Credential data model.
|
||||
*
|
||||
* @dict
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('CredentialsListDefinition', [])
|
||||
.value(
|
||||
'CredentialList', {
|
||||
|
||||
.value('CredentialList', {
|
||||
|
||||
name: 'credentials',
|
||||
iterator: 'credential',
|
||||
selectTitle: 'Add Credentials',
|
||||
editTitle: 'Credentials',
|
||||
selectInstructions: '<p>Select existing credentials by clicking each credential or checking the related checkbox. When finished, click the blue ' +
|
||||
'<em>Select</em> button, located bottom right.</p> <p>Create a brand new credential by clicking the green <em>Create New</em> button.</p>',
|
||||
selectInstructions: "<p>Select existing credentials by clicking each credential or checking the related checkbox. When " +
|
||||
"finished, click the blue <em>Select</em> button, located bottom right.</p> <p>Create a brand new credential by clicking " +
|
||||
"the green <em>Create New</em> button.</p>",
|
||||
index: true,
|
||||
hover: true,
|
||||
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
excludeModal: false
|
||||
},
|
||||
},
|
||||
kind: {
|
||||
label: 'Type',
|
||||
searchType: 'select',
|
||||
searchOptions: [], // will be set by Options call to credentials resource
|
||||
searchOptions: [], // will be set by Options call to credentials resource
|
||||
excludeModal: true,
|
||||
nosort: true
|
||||
}
|
||||
/*
|
||||
team: {
|
||||
label: 'Team',
|
||||
ngBind: 'credential.team_name',
|
||||
sourceModel: 'team',
|
||||
sourceField: 'name',
|
||||
excludeModal: true
|
||||
},
|
||||
user: {
|
||||
label: 'User',
|
||||
ngBind: 'credential.user_username',
|
||||
sourceModel: 'user',
|
||||
sourceField: 'username',
|
||||
excludeModal: true
|
||||
}
|
||||
*/
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
add: {
|
||||
mode: 'all', // One of: edit, select, all
|
||||
mode: 'all', // One of: edit, select, all
|
||||
ngClick: 'addCredential()',
|
||||
awToolTip: 'Create a new credential'
|
||||
},
|
||||
},
|
||||
stream: {
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
mode: 'all'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
ngClick: "editCredential(\{\{ credential.id \}\})",
|
||||
ngClick: "editCredential(credential.id)",
|
||||
icon: 'fa-edit',
|
||||
label: 'Edit',
|
||||
"class": 'btn-sm',
|
||||
awToolTip: 'Edit credential',
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
},
|
||||
|
||||
"delete": {
|
||||
ngClick: "deleteCredential(\{\{ credential.id \}\},'\{\{ credential.name \}\}')",
|
||||
ngClick: "deleteCredential(credential.id, credential.name)",
|
||||
icon: 'fa-trash',
|
||||
label: 'Delete',
|
||||
"class": 'btn-sm',
|
||||
awToolTip: 'Delete credential',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,60 +1,62 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* Groups.js
|
||||
* Groups.js
|
||||
* List view object for Group data model.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('GroupListDefinition', [])
|
||||
.value(
|
||||
'GroupList', {
|
||||
|
||||
.value('GroupList', {
|
||||
|
||||
name: 'groups',
|
||||
iterator: 'group',
|
||||
selectTitle: 'Copy Groups',
|
||||
editTitle: 'Groups',
|
||||
index: true,
|
||||
well: false,
|
||||
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Description'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
help: {
|
||||
help: {
|
||||
awPopOver: "Choose groups by clicking on each group you wish to add. Click the <em>Select</em> button to add the groups to " +
|
||||
"the selected inventory group.",
|
||||
dataContainer: '#form-modal .modal-content',
|
||||
mode: 'all',
|
||||
awToolTip: 'Click for help',
|
||||
dataTitle: 'Adding Groups'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "editGroup(\{\{ group.id \}\})",
|
||||
ngClick: "editGroup(group.id)",
|
||||
icon: 'icon-edit',
|
||||
"class": 'btn-xs',
|
||||
awToolTip: 'Edit group',
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
},
|
||||
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "deleteGroup(\{\{ group.id \}\},'\{\{ group.name \}\}')",
|
||||
ngClick: "deleteGroup(group.id, group.name)",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-xs',
|
||||
awToolTip: 'Delete group',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,16 +1,18 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* HomeGroups.js
|
||||
* HomeGroups.js
|
||||
*
|
||||
* List view object for Group data model. Used
|
||||
* on the home tab.
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('HomeGroupListDefinition', [])
|
||||
.value(
|
||||
'HomeGroupList', {
|
||||
|
||||
.value('HomeGroupList', {
|
||||
|
||||
name: 'home_groups',
|
||||
iterator: 'group',
|
||||
editTitle: 'Groups',
|
||||
@ -24,40 +26,46 @@ angular.module('HomeGroupListDefinition', [])
|
||||
label: 'Group',
|
||||
ngClick: "editGroup(group.id, group.inventory)",
|
||||
columnClass: 'col-lg-4 col-md3 col-sm-3 col-xs-6 ellipsis'
|
||||
},
|
||||
},
|
||||
inventory_name: {
|
||||
label: 'Inventory',
|
||||
label: 'Inventory',
|
||||
sourceModel: 'inventory',
|
||||
sourceField: 'name',
|
||||
columnClass: 'col-lg-3 col-md2 col-sm-2 hidden-xs elllipsis',
|
||||
linkTo: "\{\{ '/#/inventories/' + group.inventory + '/' \}\}"
|
||||
},
|
||||
linkTo: "{{ /#/inventories/' + group.inventory + '/' }}"
|
||||
},
|
||||
source: {
|
||||
label: 'Source',
|
||||
searchType: 'select',
|
||||
searchOptions: [
|
||||
{ name: "ec2", value: "ec2" },
|
||||
{ name: "none", value: "" },
|
||||
{ name: "rax", value: "rax" }],
|
||||
searchOptions: [{
|
||||
name: "ec2",
|
||||
value: "ec2"
|
||||
}, {
|
||||
name: "none",
|
||||
value: ""
|
||||
}, {
|
||||
name: "rax",
|
||||
value: "rax"
|
||||
}],
|
||||
sourceModel: 'inventory_source',
|
||||
sourceField: 'source',
|
||||
searchOnly: true
|
||||
},
|
||||
},
|
||||
has_external_source: {
|
||||
label: 'Has external source?',
|
||||
searchType: 'in',
|
||||
label: 'Has external source?',
|
||||
searchType: 'in',
|
||||
searchValue: 'ec2,rax',
|
||||
searchOnly: true,
|
||||
sourceModel: 'inventory_source',
|
||||
sourceField: 'source'
|
||||
},
|
||||
},
|
||||
has_active_failures: {
|
||||
label: 'Has failed hosts?',
|
||||
searchSingleValue: true,
|
||||
searchType: 'boolean',
|
||||
searchValue: 'true',
|
||||
searchOnly: true
|
||||
},
|
||||
},
|
||||
last_update_failed: {
|
||||
label: 'Update failed?',
|
||||
searchType: 'select',
|
||||
@ -66,66 +74,66 @@ angular.module('HomeGroupListDefinition', [])
|
||||
searchOnly: true,
|
||||
sourceModel: 'inventory_source',
|
||||
sourceField: 'status'
|
||||
},
|
||||
},
|
||||
id: {
|
||||
label: 'ID',
|
||||
searchOnly: true
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
sync_status: {
|
||||
mode: 'all',
|
||||
ngClick: "viewUpdateStatus(group.id, group.group_id)",
|
||||
awToolTip: "\{\{ group.status_tooltip \}\}",
|
||||
awToolTip: "{{ group.status_tooltip }}",
|
||||
ngClass: "group.status_class",
|
||||
dataPlacement: "top"
|
||||
},
|
||||
},
|
||||
failed_hosts: {
|
||||
mode: 'all',
|
||||
awToolTip: "{{ group.hosts_status_tip }}",
|
||||
dataPlacement: "top",
|
||||
ngHref: "/#/inventories/{{ group.inventory }}/",
|
||||
iconClass: "{{ 'fa icon-failures-' + group.hosts_status_class }}"
|
||||
},
|
||||
},
|
||||
group_update: {
|
||||
//label: 'Sync',
|
||||
mode: 'all',
|
||||
ngClick: 'updateGroup(\{\{ group.id \}\})',
|
||||
awToolTip: "\{\{ group.launch_tooltip \}\}",
|
||||
ngClick: 'updateGroup(group.id)',
|
||||
awToolTip: "{{ group.launch_tooltip }}",
|
||||
ngShow: "(group.status !== 'running' && group.status !== 'pending' && group.status !== 'updating')",
|
||||
ngClass: "group.launch_class",
|
||||
dataPlacement: "top"
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
//label: 'Cancel',
|
||||
mode: 'all',
|
||||
ngClick: "cancelUpdate(\{\{ group.id \}\})",
|
||||
ngClick: "cancelUpdate(group.id)",
|
||||
awToolTip: "Cancel sync process",
|
||||
'class': 'red-txt',
|
||||
ngShow: "(group.status == 'running' || group.status == 'pending' || group.status == 'updating')",
|
||||
dataPlacement: "top"
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
mode: 'all',
|
||||
ngClick: "editGroup(group.id)",
|
||||
awToolTip: 'Edit group',
|
||||
dataPlacement: "top"
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
refresh: {
|
||||
mode: 'all',
|
||||
awToolTip: "Refresh the page",
|
||||
ngClick: "refresh()"
|
||||
},
|
||||
},
|
||||
stream: {
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
mode: 'all'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
@ -1,16 +1,18 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* HomeHosts.js
|
||||
* HomeHosts.js
|
||||
*
|
||||
* List view object for Hosts data model. Used
|
||||
* on the home tab.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('HomeHostListDefinition', [])
|
||||
.value(
|
||||
'HomeHostList', {
|
||||
|
||||
.value('HomeHostList', {
|
||||
|
||||
name: 'hosts',
|
||||
iterator: 'host',
|
||||
selectTitle: 'Add Existing Hosts',
|
||||
@ -24,41 +26,41 @@ angular.module('HomeHostListDefinition', [])
|
||||
key: true,
|
||||
label: 'Name',
|
||||
columnClass: 'col-lg-4 col-md3 col-sm-3 col-xs-7 ellipsis',
|
||||
ngClick: "editHost(\{\{ host.id \}\}, '\{\{ host.name \}\}')"
|
||||
},
|
||||
ngClick: "editHost(host.id, host.name)"
|
||||
},
|
||||
inventory_name: {
|
||||
label: 'Inventory',
|
||||
label: 'Inventory',
|
||||
sourceModel: 'inventory',
|
||||
sourceField: 'name',
|
||||
columnClass: 'col-lg-3 col-md2 col-sm-2 hidden-xs elllipsis',
|
||||
linkTo: "\{\{ '/#/inventories/' + host.inventory \}\}"
|
||||
},
|
||||
linkTo: "{{ '/#/inventories/' + host.inventory }}"
|
||||
},
|
||||
enabled: {
|
||||
label: 'Disabled?',
|
||||
searchSingleValue: true,
|
||||
searchType: 'boolean',
|
||||
searchValue: 'false',
|
||||
searchOnly: true
|
||||
},
|
||||
},
|
||||
has_active_failures: {
|
||||
label: 'Has failed jobs?',
|
||||
searchSingleValue: true,
|
||||
searchType: 'boolean',
|
||||
searchValue: 'true',
|
||||
searchOnly: true
|
||||
},
|
||||
},
|
||||
has_inventory_sources: {
|
||||
label: 'Has external source?',
|
||||
searchSingleValue: true,
|
||||
searchType: 'boolean',
|
||||
searchValue: 'true',
|
||||
searchOnly: true
|
||||
},
|
||||
},
|
||||
id: {
|
||||
label: 'ID',
|
||||
searchOnly: true
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
enabled_flag: {
|
||||
@ -68,7 +70,7 @@ angular.module('HomeHostListDefinition', [])
|
||||
awToolTip: "{{ host.enabledToolTip }}",
|
||||
dataTipWatch: "host.enabledToolTip",
|
||||
ngClick: "toggleHostEnabled(host.id, host.has_inventory_sources)"
|
||||
},
|
||||
},
|
||||
active_failures: {
|
||||
//label: 'Job Status',
|
||||
//ngHref: "\{\{'/#/hosts/' + host.id + '/job_host_summaries/?inventory=' + inventory_id \}\}",
|
||||
@ -78,22 +80,22 @@ angular.module('HomeHostListDefinition', [])
|
||||
awTipPlacement: 'top',
|
||||
dataPlacement: 'left',
|
||||
iconClass: "{{ 'fa icon-failures-' + host.has_active_failures }}"
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "editHost(host.id)",
|
||||
icon: 'icon-edit',
|
||||
awToolTip: 'Edit host',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
stream: {
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
mode: 'all'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
@ -1,15 +1,17 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* Hosts.js
|
||||
* Hosts.js
|
||||
* List view object for Users data model.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('HostListDefinition', [])
|
||||
.value(
|
||||
'HostList', {
|
||||
|
||||
.value('HostList', {
|
||||
|
||||
name: 'hosts',
|
||||
iterator: 'host',
|
||||
selectTitle: 'Add Existing Hosts',
|
||||
@ -21,13 +23,13 @@ angular.module('HostListDefinition', [])
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Host Name',
|
||||
linkTo: "/inventories/\{\{ inventory_id \}\}/hosts/\{\{ host.id \}\}"
|
||||
},
|
||||
linkTo: "/inventories/{{ inventory_id }}/hosts/{{ host.id }}"
|
||||
},
|
||||
description: {
|
||||
label: 'Description'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
help: {
|
||||
awPopOver: "Select hosts by clicking on each host you wish to add. Add the selected hosts to the group by clicking the <em>Select</em> button.",
|
||||
@ -35,26 +37,26 @@ angular.module('HostListDefinition', [])
|
||||
mode: 'all',
|
||||
awToolTip: 'Click for help',
|
||||
dataTitle: 'Selecting Hosts'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "editHost(\{\{ host.id \}\})",
|
||||
ngClick: "editHost({{ host.id }})",
|
||||
icon: 'icon-edit',
|
||||
"class": 'btn-xs',
|
||||
awToolTip: 'Edit host',
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
},
|
||||
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "deleteHost(\{\{ host.id \}\},'\{\{ host.name \}\}')",
|
||||
ngClick: "deleteHost(host.id, host.name)",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-xs',
|
||||
awToolTip: 'Delete host',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,27 +1,30 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* Inventories.js
|
||||
* Inventories.js
|
||||
* List view object for Inventories data model.
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('InventoriesListDefinition', [])
|
||||
.value(
|
||||
'InventoryList', {
|
||||
|
||||
.value('InventoryList', {
|
||||
|
||||
name: 'inventories',
|
||||
iterator: 'inventory',
|
||||
selectTitle: 'Add Inventories',
|
||||
editTitle: 'Inventories',
|
||||
selectInstructions: 'Click on a row to select it, and click Finished when done. Use the green <i class=\"icon-plus\"></i> button to create a new row.',
|
||||
selectInstructions: "Click on a row to select it, and click Finished when done. Use the green <i class=\"icon-plus\"></i> " +
|
||||
"button to create a new row.",
|
||||
index: true,
|
||||
hover: true,
|
||||
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
organization: {
|
||||
label: 'Organization',
|
||||
ngBind: 'inventory.summary_fields.organization.name',
|
||||
@ -29,69 +32,69 @@ angular.module('InventoriesListDefinition', [])
|
||||
sourceModel: 'organization',
|
||||
sourceField: 'name',
|
||||
excludeModal: true
|
||||
},
|
||||
},
|
||||
has_inventory_sources: {
|
||||
label: 'Cloud sourced?',
|
||||
searchSingleValue: true,
|
||||
searchType: 'boolean',
|
||||
searchValue: 'true',
|
||||
searchOnly: true
|
||||
},
|
||||
},
|
||||
has_active_failures: {
|
||||
label: 'Failed hosts?',
|
||||
searchSingleValue: true,
|
||||
searchType: 'boolean',
|
||||
searchValue: 'true',
|
||||
searchOnly: true
|
||||
},
|
||||
},
|
||||
inventory_sources_with_failures: {
|
||||
label: 'Sync failures?',
|
||||
searchType: 'gtzero',
|
||||
searchValue: 'true',
|
||||
searchOnly: true
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
add: {
|
||||
mode: 'all', // One of: edit, select, all
|
||||
mode: 'all', // One of: edit, select, all
|
||||
ngClick: 'addInventory()',
|
||||
awToolTip: 'Create a new inventory'
|
||||
},
|
||||
},
|
||||
stream: {
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
icon: "icon-comments-alt",
|
||||
mode: 'all'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
status: {
|
||||
status: {
|
||||
//label: 'Status',
|
||||
ngHref: "\{\{ inventory.status_link \}\}",
|
||||
iconClass: "\{\{ 'fa fa-cloud icon-cloud-' + inventory.status_class \}\}",
|
||||
awToolTip: "\{\{ inventory.status_tip \}\}",
|
||||
ngHref: "inventory.status_link",
|
||||
iconClass: "{{ 'fa fa-cloud icon-cloud-' + inventory.status_class }}",
|
||||
awToolTip: "{{ inventory.status_tip }}",
|
||||
dataPlacement: "top"
|
||||
},
|
||||
failed_hosts: {
|
||||
},
|
||||
failed_hosts: {
|
||||
//label: 'Failures',
|
||||
ngHref: "\{\{ inventory.failed_hosts_link \}\}",
|
||||
iconClass: "\{\{ 'fa icon-failures-' + inventory.failed_hosts_class \}\}",
|
||||
awToolTip: "\{\{ inventory.failed_hosts_tip \}\}",
|
||||
ngHref: "inventory.failed_hosts_link",
|
||||
iconClass: "{{ 'fa icon-failures-' + inventory.failed_hosts_class }}",
|
||||
awToolTip: "{{ inventory.failed_hosts_tip }}",
|
||||
dataPlacement: "top"
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: 'editInventoryProperties(inventory.id)',
|
||||
awToolTip: 'Edit inventory',
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
},
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "deleteInventory(\{\{ inventory.id \}\},'\{\{ inventory.name \}\}')",
|
||||
ngClick: "deleteInventory(inventory.id, inventory.names')",
|
||||
awToolTip: 'Delete inventory',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,14 +1,16 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* InventoryHosts.js
|
||||
* InventoryHosts.js
|
||||
*
|
||||
* Right side of /inventories/N page, showing hosts in the selected group.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('InventoryHostsDefinition', [])
|
||||
.value(
|
||||
'InventoryHosts', {
|
||||
.value('InventoryHosts', {
|
||||
|
||||
name: 'hosts',
|
||||
iterator: 'host',
|
||||
@ -19,34 +21,34 @@ angular.module('InventoryHostsDefinition', [])
|
||||
hover: false,
|
||||
hasChildren: true,
|
||||
'class': 'table-condensed table-no-border',
|
||||
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Hosts',
|
||||
ngClick: "editHost(\{\{ host.id \}\})",
|
||||
ngClick: "editHost(host.id)",
|
||||
searchPlaceholder: "search_place_holder",
|
||||
columnClass: 'col-lg-9 col-md-9 col-sm-7 col-xs-7',
|
||||
dataHostId: "\{\{ host.id \}\}",
|
||||
dataHostId: "{{ host.id }}",
|
||||
dataType: "host",
|
||||
awDraggable: "true"
|
||||
},
|
||||
},
|
||||
enabled: {
|
||||
label: 'Disabled?',
|
||||
searchSingleValue: true,
|
||||
searchType: 'boolean',
|
||||
searchValue: 'false',
|
||||
searchOnly: true
|
||||
},
|
||||
},
|
||||
has_active_failures: {
|
||||
label: 'Failed jobs?',
|
||||
searchSingleValue: true,
|
||||
searchType: 'boolean',
|
||||
searchValue: 'true',
|
||||
searchOnly: true
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
enabled_flag: {
|
||||
iconClass: "{{ 'fa icon-enabled-' + host.enabled }}",
|
||||
@ -54,7 +56,7 @@ angular.module('InventoryHostsDefinition', [])
|
||||
awToolTip: "{{ host.enabledToolTip }}",
|
||||
dataTipWatch: "host.enabledToolTip",
|
||||
ngClick: "toggleHostEnabled(host.id, host.has_inventory_sources)"
|
||||
},
|
||||
},
|
||||
active_failures: {
|
||||
awPopOver: "{{ host.job_status_html }}",
|
||||
dataTitle: "{{ host.job_status_title }}",
|
||||
@ -62,22 +64,22 @@ angular.module('InventoryHostsDefinition', [])
|
||||
awTipPlacement: 'top',
|
||||
dataPlacement: 'left',
|
||||
iconClass: "{{ 'fa icon-failures-' + host.has_active_failures }}"
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
//label: 'Edit',
|
||||
ngClick: "editHost(\{\{ host.id \}\})",
|
||||
ngClick: "editHost(host.id)",
|
||||
icon: 'icon-edit',
|
||||
awToolTip: 'Edit host',
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
},
|
||||
"delete": {
|
||||
//label: 'Delete',
|
||||
ngClick: "deleteHost(\{\{ host.id \}\},'\{\{ host.name \}\}')",
|
||||
ngClick: "deleteHost(host.id, host.name)",
|
||||
icon: 'icon-trash',
|
||||
awToolTip: 'Delete host',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
|
||||
@ -86,15 +88,14 @@ angular.module('InventoryHostsDefinition', [])
|
||||
create: {
|
||||
mode: 'all',
|
||||
ngClick: "createHost()",
|
||||
ngHide: 'selected_tree_id == 1', //disable when 'All Hosts' selected
|
||||
ngHide: 'selected_tree_id == 1', //disable when 'All Hosts' selected
|
||||
awToolTip: "Create a new host"
|
||||
},
|
||||
},
|
||||
stream: {
|
||||
ngClick: "showHostActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
mode: 'all'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@ -1,15 +1,17 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* Jobs.js
|
||||
* Jobs.js
|
||||
* List view object for Team data model.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('JobEventsListDefinition', [])
|
||||
.value(
|
||||
'JobEventList', {
|
||||
|
||||
.value('JobEventList', {
|
||||
|
||||
name: 'jobevents',
|
||||
iterator: 'jobevent',
|
||||
editTitle: 'Job Events',
|
||||
@ -37,7 +39,7 @@ angular.module('JobEventsListDefinition', [])
|
||||
icon: 'icon-laptop'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
fields: {
|
||||
created: {
|
||||
label: 'Created On',
|
||||
@ -53,7 +55,13 @@ angular.module('JobEventsListDefinition', [])
|
||||
columnClass: 'col-sm-1 col-xs-2 text-center',
|
||||
searchField: 'failed',
|
||||
searchType: 'boolean',
|
||||
searchOptions: [{ name: 'success', value: 0 }, { name: 'error', value: 1 }],
|
||||
searchOptions: [{
|
||||
name: 'success',
|
||||
value: 0
|
||||
}, {
|
||||
name: 'error',
|
||||
value: 1
|
||||
}],
|
||||
nosort: true,
|
||||
searchable: false,
|
||||
ngClick: 'viewJobEvent({{ jobevent.id }})',
|
||||
@ -86,7 +94,7 @@ angular.module('JobEventsListDefinition', [])
|
||||
columnClass: 'col-lg-2 hidden-sm hidden-xs'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
actions: {
|
||||
refresh: {
|
||||
mode: 'all',
|
||||
@ -106,4 +114,4 @@ angular.module('JobEventsListDefinition', [])
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -1,20 +1,23 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* JobHosts.js
|
||||
* JobHosts.js
|
||||
* List view object for Job Host Summary data model.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('JobHostDefinition', [])
|
||||
.value('JobHostList', {
|
||||
|
||||
|
||||
name: 'jobhosts',
|
||||
iterator: 'jobhost',
|
||||
editTitle: 'All summaries',
|
||||
index: true,
|
||||
hover: true,
|
||||
|
||||
|
||||
navigationLinks: {
|
||||
ngHide: 'host_id !== null',
|
||||
details: {
|
||||
@ -64,7 +67,13 @@ angular.module('JobHostDefinition', [])
|
||||
dataPlacement: 'top',
|
||||
searchField: 'failed',
|
||||
searchType: 'boolean',
|
||||
searchOptions: [{ name: "success", value: 0 }, { name: "error", value: 1 }]
|
||||
searchOptions: [{
|
||||
name: "success",
|
||||
value: 0
|
||||
}, {
|
||||
name: "error",
|
||||
value: 1
|
||||
}]
|
||||
},
|
||||
failed: {
|
||||
label: 'Job failed?',
|
||||
@ -99,7 +108,7 @@ angular.module('JobHostDefinition', [])
|
||||
searchable: false
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
actions: {
|
||||
help: {
|
||||
awPopOver: "<dl>\n<dt>Success</dt><dd>Tasks successfully executed on the host.</dd>\n" +
|
||||
@ -121,10 +130,10 @@ angular.module('JobHostDefinition', [])
|
||||
'class': 'btn-xs',
|
||||
awToolTip: "Refresh the page",
|
||||
ngClick: "refresh()",
|
||||
ngShow: "host_id == null" //don't show when viewing from inventory->hosts
|
||||
ngShow: "host_id == null" //don't show when viewing from inventory->hosts
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {}
|
||||
|
||||
});
|
||||
});
|
||||
@ -1,73 +1,76 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* JobTemplates.js
|
||||
* JobTemplates.js
|
||||
* List view object for Job Templates data model.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('JobTemplatesListDefinition', [])
|
||||
.value(
|
||||
'JobTemplateList', {
|
||||
|
||||
.value('JobTemplateList', {
|
||||
|
||||
name: 'job_templates',
|
||||
iterator: 'job_template',
|
||||
selectTitle: 'Add Job Template',
|
||||
editTitle: 'Job Templates',
|
||||
selectInstructions: 'Click on a row to select it, and click Finished when done. Use the green <i class=\"icon-plus\"></i> button to create a new row.',
|
||||
selectInstructions: "Click on a row to select it, and click Finished when done. Use the green <i class=\"icon-plus\"></i> " +
|
||||
"button to create a new row.",
|
||||
index: true,
|
||||
hover: true,
|
||||
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Description'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
add: {
|
||||
mode: 'all', // One of: edit, select, all
|
||||
mode: 'all', // One of: edit, select, all
|
||||
ngClick: 'addJobTemplate()',
|
||||
basePaths: ['job_templates'],
|
||||
basePaths: ['job_templates'],
|
||||
awToolTip: 'Create a new template'
|
||||
},
|
||||
},
|
||||
stream: {
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
icon: "icon-comments-alt",
|
||||
mode: 'all'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "editJobTemplate(\{\{ job_template.id \}\})",
|
||||
ngClick: "editJobTemplate(job_template.id)",
|
||||
icon: 'icon-edit',
|
||||
awToolTip: 'Edit template',
|
||||
"class": 'btn-default btn-xs',
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
},
|
||||
submit: {
|
||||
label: 'Launch',
|
||||
icon: 'icon-rocket',
|
||||
mode: 'all',
|
||||
"class": 'btn-xs btn-success',
|
||||
ngClick: 'submitJob(\{\{ job_template.id \}\})',
|
||||
ngClick: 'submitJob(job_template.id)',
|
||||
awToolTip: 'Start a job using this template',
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "deleteJobTemplate(\{\{ job_template.id \}\},'\{\{ job_template.name \}\}')",
|
||||
ngClick: "deleteJobTemplate(job_template.id, job_template.name)",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-danger btn-xs',
|
||||
awToolTip: 'Delete template',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -6,6 +6,9 @@
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('JobsListDefinition', [])
|
||||
.value( 'JobList', {
|
||||
|
||||
|
||||
@ -1,44 +1,46 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* Organizations.js
|
||||
* Organizations.js
|
||||
* List view object for Organizations data model.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('OrganizationListDefinition', [])
|
||||
.value(
|
||||
'OrganizationList', {
|
||||
|
||||
.value('OrganizationList', {
|
||||
|
||||
name: 'organizations',
|
||||
iterator: 'organization',
|
||||
selectTitle: 'Add Organizations',
|
||||
editTitle: 'Organizations',
|
||||
hover: true,
|
||||
index: true,
|
||||
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
description: {
|
||||
label: 'Description'
|
||||
}
|
||||
},
|
||||
|
||||
description: {
|
||||
label: 'Description'
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
add: {
|
||||
mode: 'all', // One of: edit, select, all
|
||||
mode: 'all', // One of: edit, select, all
|
||||
ngClick: 'addOrganization()',
|
||||
awToolTip: 'Create a new organization'
|
||||
},
|
||||
},
|
||||
stream: {
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
mode: 'all'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
@ -48,7 +50,7 @@ angular.module('OrganizationListDefinition', [])
|
||||
"class": 'btn-xs btn-default',
|
||||
awToolTip: 'Edit organization',
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
},
|
||||
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
@ -57,6 +59,6 @@ angular.module('OrganizationListDefinition', [])
|
||||
"class": 'btn-xs btn-danger',
|
||||
awToolTip: 'Delete organization',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,78 +1,81 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* Permissions.js
|
||||
* Permissions.js
|
||||
* List view object for Permissions data model.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('PermissionListDefinition', [])
|
||||
.value(
|
||||
'PermissionList', {
|
||||
|
||||
.value('PermissionList', {
|
||||
|
||||
name: 'permissions',
|
||||
iterator: 'permission',
|
||||
selectTitle: 'Add Permission',
|
||||
selectInstructions: 'Click on a row to select it, and click Finished when done. Use the green <i class=\"icon-plus\"></i> button to create a new row.',
|
||||
selectInstructions: "Click on a row to select it, and click Finished when done. Use the green <i class=\"icon-plus\"></i> " +
|
||||
"button to create a new row.",
|
||||
editTitle: 'Permissions',
|
||||
index: true,
|
||||
well: true,
|
||||
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name',
|
||||
ngClick: 'editPermission(\{\{ permission.id \}\})'
|
||||
},
|
||||
ngClick: 'editPermission(permission.id)'
|
||||
},
|
||||
inventory: {
|
||||
label: 'Inventory',
|
||||
sourceModel: 'inventory',
|
||||
sourceField: 'name',
|
||||
ngBind: 'permission.summary_fields.inventory.name'
|
||||
},
|
||||
},
|
||||
project: {
|
||||
label: 'Project',
|
||||
sourceModel: 'project',
|
||||
sourceField: 'name',
|
||||
ngBind: 'permission.summary_fields.project.name'
|
||||
},
|
||||
},
|
||||
permission_type: {
|
||||
label: 'Permission'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
add: {
|
||||
mode: 'all', // One of: edit, select, all
|
||||
mode: 'all', // One of: edit, select, all
|
||||
ngClick: 'addPermission()',
|
||||
awToolTip: 'Add a new permission',
|
||||
ngShow: 'PermissionAddAllowed'
|
||||
},
|
||||
},
|
||||
stream: {
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
mode: 'all'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "editPermission(\{\{ permission.id \}\})",
|
||||
ngClick: "editPermission(permission.id)",
|
||||
icon: 'icon-edit',
|
||||
"class": 'btn-xs btn-default',
|
||||
awToolTip: 'Edit permission',
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
},
|
||||
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "deletePermission(\{\{ permission.id \}\},'\{\{ permission.name \}\}')",
|
||||
ngClick: "deletePermission(permission.id, permission.name)",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-xs btn-danger',
|
||||
awToolTip: 'Delete permission',
|
||||
ngShow: 'PermissionAddAllowed',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,66 +1,68 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* Projects.js
|
||||
* Projects.js
|
||||
* List view object for Project data model.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('ProjectsListDefinition', [])
|
||||
.value(
|
||||
'ProjectList', {
|
||||
|
||||
.value('ProjectList', {
|
||||
|
||||
name: 'projects',
|
||||
iterator: 'project',
|
||||
selectTitle: 'Add Project',
|
||||
editTitle: 'Projects',
|
||||
selectInstructions: '<p>Select existing projects by clicking each project or checking the related checkbox. When finished, click the blue ' +
|
||||
'<em>Select</em> button, located bottom right.</p> <p>Create a brand new project by clicking the green <em>Create New</em> button.</p>',
|
||||
'<em>Select</em> button, located bottom right.</p> <p>Create a brand new project by clicking the green <em>Create New</em> button.</p>',
|
||||
index: true,
|
||||
hover: true,
|
||||
|
||||
hover: true,
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Description',
|
||||
columnClass: 'hidden-sm hidden-xs',
|
||||
excludeModal: true
|
||||
},
|
||||
},
|
||||
scm_type: {
|
||||
label: 'Type',
|
||||
searchType: 'select',
|
||||
searchOptions: [], // will be set by Options call to projects resource
|
||||
searchOptions: [], // will be set by Options call to projects resource
|
||||
excludeModal: true,
|
||||
nosort: true
|
||||
},
|
||||
},
|
||||
status: {
|
||||
label: 'Status',
|
||||
ngClick: 'showSCMStatus(\{\{ project.id \}\})',
|
||||
ngClick: 'showSCMStatus(project.id)',
|
||||
awToolTip: 'View details of last SCM Update',
|
||||
dataPlacement: 'top',
|
||||
badgeIcon: "\{\{ 'fa icon-failures-' + project.badge \}\}",
|
||||
badgeIcon: "{{ 'fa icon-failures-' + project.badge }}",
|
||||
badgePlacement: 'left',
|
||||
searchType: 'select',
|
||||
searchOptions: [], // will be set by Options call to projects resource
|
||||
searchOptions: [], // will be set by Options call to projects resource
|
||||
excludeModal: true
|
||||
},
|
||||
},
|
||||
last_updated: {
|
||||
label: 'Last Updated',
|
||||
type: 'date',
|
||||
excludeModal: true,
|
||||
searchable: false
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
add: {
|
||||
mode: 'all', // One of: edit, select, all
|
||||
mode: 'all', // One of: edit, select, all
|
||||
ngClick: 'addProject()',
|
||||
awToolTip: 'Create a new project'
|
||||
},
|
||||
},
|
||||
help: {
|
||||
awPopOver: "<dl>\n<dt>Updating</dt><dd>A source control update is in progress.</dd>\n" +
|
||||
"<dt>Never Updated</dt><dd>This project has not yet been updated from source control.</dd>\n" +
|
||||
@ -75,46 +77,46 @@ angular.module('ProjectsListDefinition', [])
|
||||
mode: 'all',
|
||||
awToolTip: 'Click for help',
|
||||
awTipPlacement: 'top'
|
||||
},
|
||||
},
|
||||
refresh: {
|
||||
mode: 'all',
|
||||
awToolTip: "Refresh the page",
|
||||
ngClick: "refresh()"
|
||||
},
|
||||
},
|
||||
stream: {
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
mode: 'all'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "editProject(\{\{ project.id \}\})",
|
||||
ngClick: "editProject(project.id)",
|
||||
awToolTip: 'Edit project properties',
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
},
|
||||
scm_update: {
|
||||
label: 'Update',
|
||||
ngClick: 'SCMUpdate(\{\{ project.id \}\})',
|
||||
awToolTip: "\{\{ project.scm_update_tooltip \}\}",
|
||||
ngClick: 'SCMUpdate(project.id)',
|
||||
awToolTip: "{{ project.scm_update_tooltip }}",
|
||||
ngClass: "project.scm_type_class",
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
label: 'Stop',
|
||||
ngClick: "cancelUpdate(\{\{ project.id \}\}, '\{\{ project.name \}\}')",
|
||||
ngClick: "cancelUpdate(project.id, project.name)",
|
||||
awToolTip: 'Cancel a running SCM update process',
|
||||
ngShow: "project.status == 'updating'",
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
},
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "deleteProject(\{\{ project.id \}\},'\{\{ project.name \}\}')",
|
||||
ngClick: "deleteProject(project.id, project.name)",
|
||||
awToolTip: 'Permanently remove project from the database',
|
||||
ngShow: "project.status !== 'updating'",
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,24 +1,26 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* Streams.js
|
||||
* Streams.js
|
||||
* List view object for activity stream data model.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('StreamListDefinition', [])
|
||||
.value(
|
||||
'StreamList', {
|
||||
|
||||
.value('StreamList', {
|
||||
|
||||
name: 'activities',
|
||||
iterator: 'activity',
|
||||
editTitle: 'Activity Stream',
|
||||
selectInstructions: '',
|
||||
selectInstructions: '',
|
||||
index: false,
|
||||
hover: true,
|
||||
"class": "table-condensed",
|
||||
searchWidgets: 3,
|
||||
|
||||
|
||||
fields: {
|
||||
timestamp: {
|
||||
label: 'Event Time',
|
||||
@ -26,7 +28,7 @@ angular.module('StreamListDefinition', [])
|
||||
desc: true,
|
||||
noLink: true,
|
||||
searchable: false
|
||||
},
|
||||
},
|
||||
user: {
|
||||
label: 'Initiated by',
|
||||
ngBindHtml: 'activity.user',
|
||||
@ -36,22 +38,22 @@ angular.module('StreamListDefinition', [])
|
||||
//dataPlacement: 'top',
|
||||
searchPlaceholder: 'Username',
|
||||
searchWidget: 1
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Action',
|
||||
ngBindHtml: 'activity.description',
|
||||
nosort: true,
|
||||
nosort: true,
|
||||
searchable: false,
|
||||
columnClass: 'col-lg-7'
|
||||
},
|
||||
},
|
||||
system_event: {
|
||||
label: 'System event',
|
||||
searchOnly: true,
|
||||
searchOnly: true,
|
||||
searchType: 'isnull',
|
||||
sourceModel: 'actor',
|
||||
sourceField: 'username',
|
||||
searchWidget: 1
|
||||
},
|
||||
},
|
||||
|
||||
// The following fields exist to force loading each type of object into the search
|
||||
// dropdown
|
||||
@ -61,7 +63,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchObject: 'all',
|
||||
searchPlaceholder: 'All resources',
|
||||
searchWidget: 2
|
||||
},
|
||||
},
|
||||
credential_search: {
|
||||
label: 'Credential',
|
||||
searchOnly: true,
|
||||
@ -69,7 +71,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Credential name',
|
||||
searchWidget: 2,
|
||||
searchField: 'object1'
|
||||
},
|
||||
},
|
||||
group_search: {
|
||||
label: 'Group',
|
||||
searchOnly: true,
|
||||
@ -77,7 +79,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Group name',
|
||||
searchWidget: 2,
|
||||
searchField: 'object1'
|
||||
},
|
||||
},
|
||||
host_search: {
|
||||
label: 'Host',
|
||||
searchOnly: true,
|
||||
@ -85,7 +87,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Host name',
|
||||
searchWidget: 2,
|
||||
searchField: 'object1'
|
||||
},
|
||||
},
|
||||
inventory_search: {
|
||||
label: 'Inventory',
|
||||
searchOnly: true,
|
||||
@ -93,7 +95,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Inventory name',
|
||||
searchWidget: 2,
|
||||
searchField: 'object1'
|
||||
},
|
||||
},
|
||||
job_template_search: {
|
||||
label: 'Job Template',
|
||||
searchOnly: true,
|
||||
@ -101,7 +103,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Job template name',
|
||||
searchWidget: 2,
|
||||
searchField: 'object1'
|
||||
},
|
||||
},
|
||||
job_search: {
|
||||
label: 'Job',
|
||||
searchOnly: true,
|
||||
@ -110,7 +112,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchOnID: true,
|
||||
searchWidget: 2,
|
||||
searchField: 'object1'
|
||||
},
|
||||
},
|
||||
organization_search: {
|
||||
label: 'Organization',
|
||||
searchOnly: true,
|
||||
@ -118,7 +120,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Organization name',
|
||||
searchWidget: 2,
|
||||
searchField: 'object1'
|
||||
},
|
||||
},
|
||||
project_search: {
|
||||
label: 'Project',
|
||||
searchOnly: true,
|
||||
@ -126,7 +128,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Project name',
|
||||
searchWidget: 2,
|
||||
searchField: 'object1'
|
||||
},
|
||||
},
|
||||
user_search: {
|
||||
label: 'User',
|
||||
searchOnly: true,
|
||||
@ -134,18 +136,18 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Primary username',
|
||||
searchWidget: 2,
|
||||
searchField: 'object1'
|
||||
},
|
||||
},
|
||||
|
||||
// The following fields exist to force loading each type of object into the search
|
||||
// dropdown
|
||||
all_objects3: {
|
||||
label: 'All',
|
||||
searchOnly: true,
|
||||
searchOnly: true,
|
||||
searchObject: 'all',
|
||||
searchPlaceholder: 'All related resources',
|
||||
searchWidget: 3,
|
||||
searchField: 'object2'
|
||||
},
|
||||
},
|
||||
credential_search3: {
|
||||
label: 'Credential',
|
||||
searchOnly: true,
|
||||
@ -153,7 +155,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Related credential name',
|
||||
searchWidget: 3,
|
||||
searchField: 'object2'
|
||||
},
|
||||
},
|
||||
group_search3: {
|
||||
label: 'Group',
|
||||
searchOnly: true,
|
||||
@ -161,7 +163,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Related group name',
|
||||
searchWidget: 3,
|
||||
searchField: 'object2'
|
||||
},
|
||||
},
|
||||
host_search3: {
|
||||
label: 'Host',
|
||||
searchOnly: true,
|
||||
@ -169,7 +171,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Related host name',
|
||||
searchWidget: 3,
|
||||
searchField: 'object2'
|
||||
},
|
||||
},
|
||||
inventory_search3: {
|
||||
label: 'Inventory',
|
||||
searchOnly: true,
|
||||
@ -177,7 +179,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Related inventory name',
|
||||
searchWidget: 3,
|
||||
searchField: 'object2'
|
||||
},
|
||||
},
|
||||
job_search3: {
|
||||
label: 'Job',
|
||||
searchOnly: true,
|
||||
@ -186,7 +188,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchOnID: true,
|
||||
searchWidget: 3,
|
||||
searchField: 'object2'
|
||||
},
|
||||
},
|
||||
job_template_search3: {
|
||||
label: 'Job Template',
|
||||
searchOnly: true,
|
||||
@ -194,7 +196,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Related job template name',
|
||||
searchWidget: 3,
|
||||
searchField: 'object2'
|
||||
},
|
||||
},
|
||||
organization_search3: {
|
||||
label: 'Organization',
|
||||
searchOnly: true,
|
||||
@ -202,7 +204,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Related organization name',
|
||||
searchWidget: 3,
|
||||
searchField: 'object2'
|
||||
},
|
||||
},
|
||||
project_search3: {
|
||||
label: 'Project',
|
||||
searchOnly: true,
|
||||
@ -210,7 +212,7 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Related project name',
|
||||
searchWidget: 3,
|
||||
searchField: 'object2'
|
||||
},
|
||||
},
|
||||
user_search3: {
|
||||
label: 'User',
|
||||
searchOnly: true,
|
||||
@ -218,32 +220,32 @@ angular.module('StreamListDefinition', [])
|
||||
searchPlaceholder: 'Related username',
|
||||
searchWidget: 3,
|
||||
searchField: 'object2'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
refresh: {
|
||||
mode: 'all',
|
||||
'class': 'btn-xs',
|
||||
awToolTip: "Refresh the page",
|
||||
ngClick: "refreshStream()"
|
||||
},
|
||||
},
|
||||
close: {
|
||||
mode: 'all',
|
||||
awToolTip: "Close Activity Stream view",
|
||||
ngClick: "closeStream()"
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
view: {
|
||||
label: 'View',
|
||||
ngClick: "showDetail(\{\{ activity.id \}\})",
|
||||
ngClick: "showDetail(activity.id)",
|
||||
icon: 'fa-zoom-in',
|
||||
"class": 'btn-default btn-xs',
|
||||
awToolTip: 'View event details',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
@ -1,69 +1,71 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* Teams.js
|
||||
* Teams.js
|
||||
* List view object for Team data model.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('TeamsListDefinition', [])
|
||||
.value(
|
||||
'TeamList', {
|
||||
|
||||
.value('TeamList', {
|
||||
|
||||
name: 'teams',
|
||||
iterator: 'team',
|
||||
selectTitle: 'Add Team',
|
||||
editTitle: 'Teams',
|
||||
selectInstructions: 'Click on a row to select it, and click Finished when done. Use the green <i class=\"icon-plus\"></i> button to create a new row.',
|
||||
selectInstructions: "Click on a row to select it, and click Finished when done. Use the green <i class=\"icon-plus\"></i> " +
|
||||
"button to create a new row.",
|
||||
index: true,
|
||||
hover: true,
|
||||
hover: true,
|
||||
|
||||
fields: {
|
||||
name: {
|
||||
key: true,
|
||||
label: 'Name'
|
||||
},
|
||||
},
|
||||
description: {
|
||||
label: 'Description'
|
||||
},
|
||||
},
|
||||
organization: {
|
||||
label: 'Organization',
|
||||
ngBind: 'team.organization_name',
|
||||
sourceModel: 'organization',
|
||||
sourceField: 'name'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
add: {
|
||||
mode: 'all', // One of: edit, select, all
|
||||
mode: 'all', // One of: edit, select, all
|
||||
ngClick: 'addTeam()',
|
||||
awToolTip: 'Create a new team'
|
||||
},
|
||||
},
|
||||
stream: {
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
mode: 'all'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "editTeam(\{\{ team.id \}\})",
|
||||
ngClick: "editTeam(team.id)",
|
||||
icon: 'icon-edit',
|
||||
"class": 'btn-xs btn-default',
|
||||
awToolTip: 'Edit team',
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
},
|
||||
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "deleteTeam(\{\{ team.id \}\},'\{\{ team.name \}\}')",
|
||||
ngClick: "deleteTeam(team.id, team.name)",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-xs btn-danger',
|
||||
awToolTip: 'Delete team',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,71 +1,72 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* Users.js
|
||||
* Users.js
|
||||
* List view object for Users data model.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('UserListDefinition', [])
|
||||
.value(
|
||||
'UserList', {
|
||||
|
||||
.value('UserList', {
|
||||
|
||||
name: 'users',
|
||||
iterator: 'user',
|
||||
selectTitle: 'Add Users',
|
||||
editTitle: 'Users',
|
||||
selectInstructions: '<p>Select existing users by clicking each user or checking the related checkbox. When finished, click the blue ' +
|
||||
'<em>Select</em> button, located bottom right.</p> <p>When available, a brand new user can be created by clicking the green ' +
|
||||
'<em>Create New</em> button.</p>',
|
||||
'<em>Create New</em> button.</p>',
|
||||
index: true,
|
||||
hover: true,
|
||||
|
||||
hover: true,
|
||||
|
||||
fields: {
|
||||
username: {
|
||||
key: true,
|
||||
label: 'Username'
|
||||
},
|
||||
},
|
||||
first_name: {
|
||||
label: 'First Name'
|
||||
},
|
||||
},
|
||||
last_name: {
|
||||
label: 'Last Name'
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
add: {
|
||||
label: 'Create New',
|
||||
mode: 'all', // One of: edit, select, all
|
||||
mode: 'all', // One of: edit, select, all
|
||||
ngClick: 'addUser()',
|
||||
basePaths: ['organizations','users'], // base path must be in list, or action not available
|
||||
basePaths: ['organizations', 'users'], // base path must be in list, or action not available
|
||||
"class": 'btn-xs',
|
||||
awToolTip: 'Create a new user'
|
||||
},
|
||||
},
|
||||
stream: {
|
||||
ngClick: "showActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
mode: 'all'
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
fieldActions: {
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
ngClick: "editUser(\{\{ user.id \}\})",
|
||||
ngClick: "editUser(user.id)",
|
||||
icon: 'icon-edit',
|
||||
"class": 'btn-xs btn-default',
|
||||
awToolTip: 'Edit user',
|
||||
dataPlacement: 'top'
|
||||
},
|
||||
},
|
||||
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
ngClick: "deleteUser(\{\{ user.id \}\},'\{\{ user.username \}\}')",
|
||||
ngClick: "deleteUser(user.id, user.username)",
|
||||
icon: 'icon-trash',
|
||||
"class": 'btn-xs btn-danger',
|
||||
awToolTip: 'Delete user',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1,7 +1,7 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* InventorySyncStatus.js
|
||||
* InventorySyncStatus.js
|
||||
*
|
||||
* Dashboard widget showing object counts and license availability.
|
||||
*
|
||||
@ -10,94 +10,98 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('InventorySyncStatusWidget', ['RestServices', 'Utilities'])
|
||||
.factory('InventorySyncStatus', ['$rootScope', '$compile', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', 'GetChoices',
|
||||
function($rootScope, $compile, Rest, GetBasePath, ProcessErrors, Wait, GetChoices) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var target = params.target;
|
||||
var dashboard = params.dashboard;
|
||||
|
||||
var html = "<div class=\"panel panel-default\">\n";
|
||||
html += "<div class=\"panel-heading\">Inventory Sync Status</div>\n";
|
||||
html += "<div class=\"panel-body\">\n";
|
||||
html += "<table class=\"table table-condensed table-hover\">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>\n";
|
||||
html += "<th class=\"col-md-4 col-lg-3\"></th>\n";
|
||||
html += "<th class=\"col-md-2 col-lg-1 text-right\">Failed</th>\n";
|
||||
html += "<th class=\"col-md-2 col-lg-1 text-right\">Total</th>\n";
|
||||
html += "</tr>\n";
|
||||
html += "</thead>\n";
|
||||
html += "<tbody>\n";
|
||||
|
||||
function makeRow(params) {
|
||||
var label = params.label;
|
||||
var count = params.count;
|
||||
var fail = params.fail;
|
||||
var link = params.link;
|
||||
var fail_link = params.fail_link;
|
||||
var html = "<tr>\n";
|
||||
html += "<td><a href=\"" + link + "\"";
|
||||
html += (label == 'Hosts' || label == 'Groups') ? " class=\"pad-left-sm\" " : "";
|
||||
html += ">" + label + "</a></td>\n";
|
||||
html += "<td class=\"";
|
||||
html += (fail > 0) ? 'failed-column' : 'zero-column';
|
||||
html += " text-right\">";
|
||||
html += "<a href=\"" + fail_link + "\">" + fail + "</a>";
|
||||
html += "</td>\n";
|
||||
html += "<td class=\"text-right\">";
|
||||
html += "<a href=\"" + link + "\">" + count + "</a>";
|
||||
html += "</td></tr>\n";
|
||||
return html;
|
||||
.factory('InventorySyncStatus', ['$rootScope', '$compile', function ($rootScope, $compile) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
target = params.target,
|
||||
dashboard = params.dashboard,
|
||||
html, group_total, group_fail, element, src;
|
||||
|
||||
html = "<div class=\"panel panel-default\">\n";
|
||||
html += "<div class=\"panel-heading\">Inventory Sync Status</div>\n";
|
||||
html += "<div class=\"panel-body\">\n";
|
||||
html += "<table class=\"table table-condensed table-hover\">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>\n";
|
||||
html += "<th class=\"col-md-4 col-lg-3\"></th>\n";
|
||||
html += "<th class=\"col-md-2 col-lg-1 text-right\">Failed</th>\n";
|
||||
html += "<th class=\"col-md-2 col-lg-1 text-right\">Total</th>\n";
|
||||
html += "</tr>\n";
|
||||
html += "</thead>\n";
|
||||
html += "<tbody>\n";
|
||||
|
||||
function makeRow(params) {
|
||||
var label = params.label,
|
||||
count = params.count,
|
||||
fail = params.fail,
|
||||
link = params.link,
|
||||
fail_link = params.fail_link,
|
||||
html = "<tr>\n";
|
||||
html += "<td><a href=\"" + link + "\"";
|
||||
html += (label === 'Hosts' || label === 'Groups') ? " class=\"pad-left-sm\" " : "";
|
||||
html += ">" + label + "</a></td>\n";
|
||||
html += "<td class=\"";
|
||||
html += (fail > 0) ? 'failed-column' : 'zero-column';
|
||||
html += " text-right\">";
|
||||
html += "<a href=\"" + fail_link + "\">" + fail + "</a>";
|
||||
html += "</td>\n";
|
||||
html += "<td class=\"text-right\">";
|
||||
html += "<a href=\"" + link + "\">" + count + "</a>";
|
||||
html += "</td></tr>\n";
|
||||
return html;
|
||||
}
|
||||
|
||||
html += makeRow({ label: 'Inventories',
|
||||
count: (dashboard.inventories && dashboard.inventories.total_with_inventory_source) ?
|
||||
dashboard.inventories.total_with_inventory_source : 0,
|
||||
fail: (dashboard.inventories && dashboard.inventories.inventory_failed) ? dashboard.inventories.inventory_failed : 0,
|
||||
link: '/#/inventories/?has_inventory_sources=true',
|
||||
fail_link: '/#/inventories/?inventory_sources_with_failures=true'
|
||||
});
|
||||
|
||||
var group_total = 0;
|
||||
var group_fail = 0;
|
||||
if (dashboard.inventory_sources) {
|
||||
for (var src in dashboard.inventory_sources) {
|
||||
group_total += (dashboard.inventory_sources[src].total) ? dashboard.inventory_sources[src].total : 0;
|
||||
group_fail += (dashboard.inventory_sources[src].failed) ? dashboard.inventory_sources[src].failed : 0;
|
||||
}
|
||||
}
|
||||
|
||||
html += makeRow({ label: 'Groups',
|
||||
count: group_total,
|
||||
fail: group_fail,
|
||||
link: '/#/home/groups/?has_external_source=true',
|
||||
fail_link: '/#/home/groups/?status=failed'
|
||||
html += makeRow({
|
||||
label: 'Inventories',
|
||||
count: (dashboard.inventories && dashboard.inventories.total_with_inventory_source) ?
|
||||
dashboard.inventories.total_with_inventory_source : 0,
|
||||
fail: (dashboard.inventories && dashboard.inventories.inventory_failed) ? dashboard.inventories.inventory_failed : 0,
|
||||
link: '/#/inventories/?has_inventory_sources=true',
|
||||
fail_link: '/#/inventories/?inventory_sources_with_failures=true'
|
||||
});
|
||||
|
||||
// Each inventory source
|
||||
for (var src in dashboard.inventory_sources) {
|
||||
if (dashboard.inventory_sources[src].total) {
|
||||
html += makeRow({ label: dashboard.inventory_sources[src].label,
|
||||
count: (dashboard.inventory_sources[src].total) ? dashboard.inventory_sources[src].total : 0,
|
||||
fail: (dashboard.inventory_sources[src].failed) ? dashboard.inventory_sources[src].failed : 0,
|
||||
link: '/#/home/groups/?source=' + src,
|
||||
fail_link: '/#/home/groups/?status=failed&source=' + src
|
||||
group_total = 0;
|
||||
group_fail = 0;
|
||||
if (dashboard.inventory_sources) {
|
||||
for (src in dashboard.inventory_sources) {
|
||||
group_total += (dashboard.inventory_sources[src].total) ? dashboard.inventory_sources[src].total : 0;
|
||||
group_fail += (dashboard.inventory_sources[src].failed) ? dashboard.inventory_sources[src].failed : 0;
|
||||
}
|
||||
}
|
||||
|
||||
html += makeRow({
|
||||
label: 'Groups',
|
||||
count: group_total,
|
||||
fail: group_fail,
|
||||
link: '/#/home/groups/?has_external_source=true',
|
||||
fail_link: '/#/home/groups/?status=failed'
|
||||
});
|
||||
|
||||
// Each inventory source
|
||||
for (src in dashboard.inventory_sources) {
|
||||
if (dashboard.inventory_sources[src].total) {
|
||||
html += makeRow({
|
||||
label: dashboard.inventory_sources[src].label,
|
||||
count: (dashboard.inventory_sources[src].total) ? dashboard.inventory_sources[src].total : 0,
|
||||
fail: (dashboard.inventory_sources[src].failed) ? dashboard.inventory_sources[src].failed : 0,
|
||||
link: '/#/home/groups/?source=' + src,
|
||||
fail_link: '/#/home/groups/?status=failed&source=' + src
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
|
||||
var element = angular.element(document.getElementById(target));
|
||||
element.html(html);
|
||||
$compile(element)(scope);
|
||||
scope.$emit('WidgetLoaded');
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
|
||||
}
|
||||
}]);
|
||||
element = angular.element(document.getElementById(target));
|
||||
element.html(html);
|
||||
$compile(element)(scope);
|
||||
scope.$emit('WidgetLoaded');
|
||||
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -1,7 +1,7 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* JobStatus.js
|
||||
* JobStatus.js
|
||||
*
|
||||
* Dashboard widget showing object counts and license availability.
|
||||
*
|
||||
@ -11,88 +11,89 @@
|
||||
|
||||
angular.module('JobStatusWidget', ['RestServices', 'Utilities'])
|
||||
.factory('JobStatus', ['$rootScope', '$compile', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait',
|
||||
function($rootScope, $compile, Rest, GetBasePath, ProcessErrors, Wait) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var target = params.target;
|
||||
var dashboard = params.dashboard;
|
||||
|
||||
var html = '';
|
||||
var html = "<div class=\"panel panel-default\">\n";
|
||||
html += "<div class=\"panel-heading\">Job Status</div>\n";
|
||||
html += "<div class=\"panel-body\">\n";
|
||||
html += "<table class=\"table table-condensed table-hover\">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>\n";
|
||||
html += "<th class=\"col-md-4 col-lg-3\"></th>\n";
|
||||
html += "<th class=\"col-md-2 col-lg-1 text-right\">Failed</th>\n";
|
||||
html += "<th class=\"col-md-2 col-lg-1 text-right\">Total</th>\n";
|
||||
html += "</tr>\n";
|
||||
html += "</thead>\n";
|
||||
html += "<tbody>\n";
|
||||
|
||||
function makeRow(params) {
|
||||
var html = '';
|
||||
var label = params.label;
|
||||
var link = params.link;
|
||||
var fail_link = params.fail_link;
|
||||
var count = params.count;
|
||||
var fail = params.fail;
|
||||
html += "<tr>\n";
|
||||
html += "<td><a href=\"" + link + "\"";
|
||||
html += (label == 'Hosts' || label == 'Groups') ? " class=\"pad-left-sm\" " : "";
|
||||
html += ">" + label + "</a></td>\n";
|
||||
html += "<td class=\"";
|
||||
html += (fail > 0) ? 'failed-column' : 'zero-column';
|
||||
html += " text-right\">";
|
||||
html += "<a href=\"" + fail_link + "\">" + fail + "</a>";
|
||||
html += "</td>\n";
|
||||
html += "<td class=\"text-right\">"
|
||||
html += "<a href=\"" + link + "\" >" + count + "</a>";
|
||||
html += "</td></tr>\n";
|
||||
return html;
|
||||
}
|
||||
|
||||
html += makeRow({
|
||||
label: 'Jobs',
|
||||
link: '/#/jobs',
|
||||
count: (dashboard.jobs && dashboard.jobs.total) ? dashboard.jobs.total : 0,
|
||||
fail: (dashboard.jobs && dashboard.jobs.failed) ? dashboard.jobs.failed : 0,
|
||||
fail_link: '/#/jobs/?status=failed'
|
||||
});
|
||||
html += makeRow({
|
||||
label: 'Inventories',
|
||||
link: '/#/inventories',
|
||||
count: (dashboard.inventories && dashboard.inventories.total) ? dashboard.inventories.total : 0,
|
||||
fail: (dashboard.inventories && dashboard.inventories.job_failed) ? dashboard.inventories.job_failed : 0,
|
||||
fail_link: '/#/inventories/?has_active_failures=true'
|
||||
});
|
||||
html += makeRow({
|
||||
label: 'Groups',
|
||||
link: '/#/home/groups',
|
||||
count: (dashboard.groups && dashboard.groups.total) ? dashboard.groups.total : 0,
|
||||
fail: (dashboard.groups && dashboard.groups.job_failed) ? dashboard.groups.job_failed : 0,
|
||||
fail_link: '/#/home/groups/?has_active_failures=true'
|
||||
});
|
||||
html += makeRow({
|
||||
label: 'Hosts',
|
||||
link: '/#/home/hosts',
|
||||
count: (dashboard.hosts && dashboard.hosts.total) ? dashboard.hosts.total : 0,
|
||||
fail: (dashboard.hosts && dashboard.hosts.failed) ? dashboard.hosts.failed : 0,
|
||||
fail_link: '/#/home/hosts/?has_active_failures=true'
|
||||
});
|
||||
function ($rootScope, $compile) {
|
||||
return function (params) {
|
||||
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
var scope = params.scope,
|
||||
target = params.target,
|
||||
dashboard = params.dashboard,
|
||||
html = '', element;
|
||||
|
||||
html = "<div class=\"panel panel-default\">\n";
|
||||
html += "<div class=\"panel-heading\">Job Status</div>\n";
|
||||
html += "<div class=\"panel-body\">\n";
|
||||
html += "<table class=\"table table-condensed table-hover\">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>\n";
|
||||
html += "<th class=\"col-md-4 col-lg-3\"></th>\n";
|
||||
html += "<th class=\"col-md-2 col-lg-1 text-right\">Failed</th>\n";
|
||||
html += "<th class=\"col-md-2 col-lg-1 text-right\">Total</th>\n";
|
||||
html += "</tr>\n";
|
||||
html += "</thead>\n";
|
||||
html += "<tbody>\n";
|
||||
|
||||
var element = angular.element(document.getElementById(target));
|
||||
element.html(html);
|
||||
$compile(element)(scope);
|
||||
scope.$emit('WidgetLoaded');
|
||||
function makeRow(params) {
|
||||
var html = '',
|
||||
label = params.label,
|
||||
link = params.link,
|
||||
fail_link = params.fail_link,
|
||||
count = params.count,
|
||||
fail = params.fail;
|
||||
html += "<tr>\n";
|
||||
html += "<td><a href=\"" + link + "\"";
|
||||
html += (label === 'Hosts' || label === 'Groups') ? " class=\"pad-left-sm\" " : "";
|
||||
html += ">" + label + "</a></td>\n";
|
||||
html += "<td class=\"";
|
||||
html += (fail > 0) ? 'failed-column' : 'zero-column';
|
||||
html += " text-right\">";
|
||||
html += "<a href=\"" + fail_link + "\">" + fail + "</a>";
|
||||
html += "</td>\n";
|
||||
html += "<td class=\"text-right\">";
|
||||
html += "<a href=\"" + link + "\" >" + count + "</a>";
|
||||
html += "</td></tr>\n";
|
||||
return html;
|
||||
}
|
||||
|
||||
html += makeRow({
|
||||
label: 'Jobs',
|
||||
link: '/#/jobs',
|
||||
count: (dashboard.jobs && dashboard.jobs.total) ? dashboard.jobs.total : 0,
|
||||
fail: (dashboard.jobs && dashboard.jobs.failed) ? dashboard.jobs.failed : 0,
|
||||
fail_link: '/#/jobs/?status=failed'
|
||||
});
|
||||
html += makeRow({
|
||||
label: 'Inventories',
|
||||
link: '/#/inventories',
|
||||
count: (dashboard.inventories && dashboard.inventories.total) ? dashboard.inventories.total : 0,
|
||||
fail: (dashboard.inventories && dashboard.inventories.job_failed) ? dashboard.inventories.job_failed : 0,
|
||||
fail_link: '/#/inventories/?has_active_failures=true'
|
||||
});
|
||||
html += makeRow({
|
||||
label: 'Groups',
|
||||
link: '/#/home/groups',
|
||||
count: (dashboard.groups && dashboard.groups.total) ? dashboard.groups.total : 0,
|
||||
fail: (dashboard.groups && dashboard.groups.job_failed) ? dashboard.groups.job_failed : 0,
|
||||
fail_link: '/#/home/groups/?has_active_failures=true'
|
||||
});
|
||||
html += makeRow({
|
||||
label: 'Hosts',
|
||||
link: '/#/home/hosts',
|
||||
count: (dashboard.hosts && dashboard.hosts.total) ? dashboard.hosts.total : 0,
|
||||
fail: (dashboard.hosts && dashboard.hosts.failed) ? dashboard.hosts.failed : 0,
|
||||
fail_link: '/#/home/hosts/?has_active_failures=true'
|
||||
});
|
||||
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
|
||||
element = angular.element(document.getElementById(target));
|
||||
element.html(html);
|
||||
$compile(element)(scope);
|
||||
scope.$emit('WidgetLoaded');
|
||||
|
||||
};
|
||||
}
|
||||
}]);
|
||||
]);
|
||||
@ -1,7 +1,7 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* ObjectCount.js
|
||||
* ObjectCount.js
|
||||
*
|
||||
* Dashboard widget showing object counts and license availability.
|
||||
*
|
||||
@ -11,60 +11,60 @@
|
||||
|
||||
angular.module('ObjectCountWidget', ['RestServices', 'Utilities'])
|
||||
.factory('ObjectCount', ['$rootScope', '$compile', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait',
|
||||
function($rootScope, $compile, Rest, GetBasePath, ProcessErrors, Wait) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var target = params.target;
|
||||
var dashboard = params.dashboard;
|
||||
|
||||
|
||||
var keys=[ 'organizations', 'users', 'teams', 'credentials', 'projects', 'inventories', 'groups', 'hosts',
|
||||
'job_templates', 'jobs' ];
|
||||
|
||||
var html = "<div class=\"panel panel-default\">\n";
|
||||
html += "<div class=\"panel-heading\">System Summary</div>\n";
|
||||
html += "<div class=\"panel-body\">\n";
|
||||
html += "<table class=\"table table-condensed table-hover\">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>\n";
|
||||
html += "<th class=\"col-md-5 col-lg-4\"></th>\n";
|
||||
html += "<th class=\"col-md-1 col-lg-1 text-right\">Total</th>\n";
|
||||
html += "</tr>\n";
|
||||
html += "</thead>\n";
|
||||
html += "<tbody>\n";
|
||||
|
||||
function makeRow(params) {
|
||||
var html = '';
|
||||
var label = params.label;
|
||||
var link = params.link;
|
||||
var count = params.count;
|
||||
html += "<tr>\n";
|
||||
html += "<td class=\"capitalize\"><a href=\"" + link + "\"";
|
||||
html += (label == 'hosts' || label == 'groups') ? " class=\"pad-left-sm\" " : "";
|
||||
html += ">" + label.replace(/\_/g,' ') + "</a></td>\n";
|
||||
html += "<td class=\"text-right\">"
|
||||
html += "<a href=\"" + link + "\" >" + count + "</a>";
|
||||
html += "</td></tr>\n";
|
||||
return html;
|
||||
}
|
||||
|
||||
for (var i=0; i < keys.length; i++) {
|
||||
html += makeRow({
|
||||
label: keys[i],
|
||||
link: '/#/' + ( (keys[i] == 'hosts' || keys[i] == 'groups') ? 'home/' + keys[i] : keys[i] ),
|
||||
count: (dashboard[keys[i]] && dashboard[keys[i]].total) ? dashboard[keys[i]].total : 0
|
||||
});
|
||||
}
|
||||
function ($rootScope, $compile) {
|
||||
return function (params) {
|
||||
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n"
|
||||
var element = angular.element(document.getElementById(target));
|
||||
element.html(html);
|
||||
$compile(element)(scope);
|
||||
scope.$emit('WidgetLoaded');
|
||||
|
||||
var scope = params.scope,
|
||||
target = params.target,
|
||||
dashboard = params.dashboard,
|
||||
keys = ['organizations', 'users', 'teams', 'credentials', 'projects', 'inventories', 'groups', 'hosts',
|
||||
'job_templates', 'jobs'
|
||||
],
|
||||
i, html, element;
|
||||
|
||||
html = "<div class=\"panel panel-default\">\n";
|
||||
html += "<div class=\"panel-heading\">System Summary</div>\n";
|
||||
html += "<div class=\"panel-body\">\n";
|
||||
html += "<table class=\"table table-condensed table-hover\">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>\n";
|
||||
html += "<th class=\"col-md-5 col-lg-4\"></th>\n";
|
||||
html += "<th class=\"col-md-1 col-lg-1 text-right\">Total</th>\n";
|
||||
html += "</tr>\n";
|
||||
html += "</thead>\n";
|
||||
html += "<tbody>\n";
|
||||
|
||||
function makeRow(params) {
|
||||
var html = '',
|
||||
label = params.label,
|
||||
link = params.link,
|
||||
count = params.count;
|
||||
html += "<tr>\n";
|
||||
html += "<td class=\"capitalize\"><a href=\"" + link + "\"";
|
||||
html += (label === 'hosts' || label === 'groups') ? " class=\"pad-left-sm\" " : "";
|
||||
html += ">" + label.replace(/\_/g, ' ') + "</a></td>\n";
|
||||
html += "<td class=\"text-right\">";
|
||||
html += "<a href=\"" + link + "\" >" + count + "</a>";
|
||||
html += "</td></tr>\n";
|
||||
return html;
|
||||
}
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
html += makeRow({
|
||||
label: keys[i],
|
||||
link: '/#/' + ((keys[i] === 'hosts' || keys[i] === 'groups') ? 'home/' + keys[i] : keys[i]),
|
||||
count: (dashboard[keys[i]] && dashboard[keys[i]].total) ? dashboard[keys[i]].total : 0
|
||||
});
|
||||
}
|
||||
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
element = angular.element(document.getElementById(target));
|
||||
element.html(html);
|
||||
$compile(element)(scope);
|
||||
scope.$emit('WidgetLoaded');
|
||||
};
|
||||
}
|
||||
}]);
|
||||
]);
|
||||
@ -1,99 +1,100 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* SCMSyncStatus.js
|
||||
* SCMSyncStatus.js
|
||||
*
|
||||
* Dashboard widget showing object counts and license availability.
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('SCMSyncStatusWidget', ['RestServices', 'Utilities'])
|
||||
.factory('SCMSyncStatus', ['$rootScope', '$compile', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', 'GetChoices',
|
||||
function($rootScope, $compile, Rest, GetBasePath, ProcessErrors, Wait, GetChoices) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var target = params.target;
|
||||
var dashboard = params.dashboard;
|
||||
|
||||
var html = "<div class=\"panel panel-default\">\n";
|
||||
html += "<div class=\"panel-heading\">Project SCM Status</div>\n";
|
||||
html += "<div class=\"panel-body\">\n";
|
||||
html += "<table class=\"table table-condensed table-hover\">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>\n";
|
||||
html += "<th class=\"col-md-4 col-lg-3\"></th>\n";
|
||||
html += "<th class=\"col-md-2 col-lg-1 text-right\">Failed</th>\n";
|
||||
html += "<th class=\"col-md-2 col-lg-1 text-right\">Total</th>\n";
|
||||
html += "</tr>\n";
|
||||
html += "</thead>\n";
|
||||
html += "<tbody>\n";
|
||||
|
||||
function makeRow(params) {
|
||||
var html = '';
|
||||
var label = params.label;
|
||||
var link = params.link;
|
||||
var fail_link = params.fail_link;
|
||||
var count = params.count;
|
||||
var fail = params.fail;
|
||||
html += "<tr>\n";
|
||||
html += "<td><a href=\"" + link + "\">" + label + "</a></td>\n";
|
||||
html += "<td class=\"";
|
||||
html += (fail > 0) ? 'failed-column' : 'zero-column';
|
||||
html += " text-right\">";
|
||||
html += "<a href=\"" + fail_link + "\">" + fail + "</a>";
|
||||
html += "</td>\n";
|
||||
html += "<td class=\"text-right\">"
|
||||
html += "<a href=\"" + link + "\" >" + count + "</a>";
|
||||
html += "</td></tr>\n";
|
||||
return html;
|
||||
}
|
||||
.factory('SCMSyncStatus', ['$rootScope', '$compile',
|
||||
function ($rootScope, $compile) {
|
||||
return function (params) {
|
||||
|
||||
var total_count = 0;
|
||||
if (dashboard.scm_types) {
|
||||
for (var type in dashboard.scm_types) {
|
||||
total_count += (dashboard.scm_types[type].total) ? dashboard.scm_types[type].total : 0;
|
||||
}
|
||||
}
|
||||
var scope = params.scope,
|
||||
target = params.target,
|
||||
dashboard = params.dashboard,
|
||||
i, html, total_count, element, type, labelList;
|
||||
|
||||
html = "<div class=\"panel panel-default\">\n";
|
||||
html += "<div class=\"panel-heading\">Project SCM Status</div>\n";
|
||||
html += "<div class=\"panel-body\">\n";
|
||||
html += "<table class=\"table table-condensed table-hover\">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>\n";
|
||||
html += "<th class=\"col-md-4 col-lg-3\"></th>\n";
|
||||
html += "<th class=\"col-md-2 col-lg-1 text-right\">Failed</th>\n";
|
||||
html += "<th class=\"col-md-2 col-lg-1 text-right\">Total</th>\n";
|
||||
html += "</tr>\n";
|
||||
html += "</thead>\n";
|
||||
html += "<tbody>\n";
|
||||
|
||||
function makeRow(params) {
|
||||
var html = '',
|
||||
label = params.label,
|
||||
link = params.link,
|
||||
fail_link = params.fail_link,
|
||||
count = params.count,
|
||||
fail = params.fail;
|
||||
html += "<tr>\n";
|
||||
html += "<td><a href=\"" + link + "\">" + label + "</a></td>\n";
|
||||
html += "<td class=\"";
|
||||
html += (fail > 0) ? 'failed-column' : 'zero-column';
|
||||
html += " text-right\">";
|
||||
html += "<a href=\"" + fail_link + "\">" + fail + "</a>";
|
||||
html += "</td>\n";
|
||||
html += "<td class=\"text-right\">";
|
||||
html += "<a href=\"" + link + "\" >" + count + "</a>";
|
||||
html += "</td></tr>\n";
|
||||
return html;
|
||||
}
|
||||
|
||||
total_count = 0;
|
||||
if (dashboard.scm_types) {
|
||||
for (type in dashboard.scm_types) {
|
||||
total_count += (dashboard.scm_types[type].total) ? dashboard.scm_types[type].total : 0;
|
||||
}
|
||||
}
|
||||
|
||||
html += makeRow({ label: 'Projects',
|
||||
link: '/#/projects',
|
||||
count: total_count,
|
||||
fail: (dashboard.projects && dashboard.projects.failed) ? dashboard.projects.failed : 0,
|
||||
fail_link: '/#/projects/?status=failed'
|
||||
});
|
||||
|
||||
var labelList = [];
|
||||
for (var type in dashboard.scm_types) {
|
||||
labelList.push(type);
|
||||
}
|
||||
labelList.sort();
|
||||
var type;
|
||||
for (var i=0; i < labelList.length; i++) {
|
||||
type = labelList[i];
|
||||
if (dashboard.scm_types[type].total) {
|
||||
html += makeRow({
|
||||
label: dashboard.scm_types[type].label,
|
||||
link: '/#/projects/?scm_type=' + type,
|
||||
count: (dashboard.scm_types[type].total) ? dashboard.scm_types[type].total : 0,
|
||||
fail: (dashboard.scm_types[type].failed) ? dashboard.scm_types[type].failed : 0,
|
||||
fail_link: '/#/projects/?scm_type=' + type + '&status=failed'
|
||||
});
|
||||
}
|
||||
label: 'Projects',
|
||||
link: '/#/projects',
|
||||
count: total_count,
|
||||
fail: (dashboard.projects && dashboard.projects.failed) ? dashboard.projects.failed : 0,
|
||||
fail_link: '/#/projects/?status=failed'
|
||||
});
|
||||
|
||||
labelList = [];
|
||||
for (type in dashboard.scm_types) {
|
||||
labelList.push(type);
|
||||
}
|
||||
labelList.sort();
|
||||
for (i = 0; i < labelList.length; i++) {
|
||||
type = labelList[i];
|
||||
if (dashboard.scm_types[type].total) {
|
||||
html += makeRow({
|
||||
label: dashboard.scm_types[type].label,
|
||||
link: '/#/projects/?scm_type=' + type,
|
||||
count: (dashboard.scm_types[type].total) ? dashboard.scm_types[type].total : 0,
|
||||
fail: (dashboard.scm_types[type].failed) ? dashboard.scm_types[type].failed : 0,
|
||||
fail_link: '/#/projects/?scm_type=' + type + '&status=failed'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
|
||||
element = angular.element(document.getElementById(target));
|
||||
element.html(html);
|
||||
$compile(element)(scope);
|
||||
scope.$emit('WidgetLoaded');
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
|
||||
var element = angular.element(document.getElementById(target));
|
||||
element.html(html);
|
||||
$compile(element)(scope);
|
||||
scope.$emit('WidgetLoaded');
|
||||
|
||||
}
|
||||
}]);
|
||||
]);
|
||||
@ -1,7 +1,7 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* Stream.js
|
||||
* Stream.js
|
||||
*
|
||||
* Activity stream widget that can be called from anywhere
|
||||
*
|
||||
@ -10,457 +10,470 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefinition', 'SearchHelper', 'PaginationHelpers',
|
||||
'RefreshHelper', 'ListGenerator', 'StreamWidget', 'AuthService'])
|
||||
|
||||
.factory('setStreamHeight', [ function() {
|
||||
return function() {
|
||||
// Try not to overlap footer. Because stream is positioned absolute, the parent
|
||||
// doesn't resize correctly when stream is loaded.
|
||||
var sheight = $('#stream-content').height();
|
||||
var theight = parseInt($('#tab-content-container').css('min-height').replace(/px/,''));
|
||||
var height = (theight < sheight) ? sheight : theight;
|
||||
$('#tab-content-container').css({ "min-height": height });
|
||||
}
|
||||
}])
|
||||
'RefreshHelper', 'ListGenerator', 'StreamWidget', 'AuthService'
|
||||
])
|
||||
|
||||
.factory('ShowStream', [ 'setStreamHeight', 'Authorization', function(setStreamHeight, Authorization) {
|
||||
return function() {
|
||||
// Slide in the Stream widget
|
||||
|
||||
// Make some style/position adjustments adjustments
|
||||
var stream = $('#stream-container');
|
||||
stream.css({
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
'min-height': '100%',
|
||||
'background-color': '#FFF'
|
||||
.factory('setStreamHeight', [
|
||||
function () {
|
||||
return function () {
|
||||
// Try not to overlap footer. Because stream is positioned absolute, the parent
|
||||
// doesn't resize correctly when stream is loaded.
|
||||
var sheight = $('#stream-content').height(),
|
||||
theight = parseInt($('#tab-content-container').css('min-height').replace(/px/, '')),
|
||||
height = (theight < sheight) ? sheight : theight;
|
||||
$('#tab-content-container').css({
|
||||
"min-height": height
|
||||
});
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
.factory('ShowStream', ['setStreamHeight', 'Authorization',
|
||||
function (setStreamHeight) {
|
||||
return function () {
|
||||
// Slide in the Stream widget
|
||||
|
||||
// Make some style/position adjustments adjustments
|
||||
var stream = $('#stream-container');
|
||||
stream.css({
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
'min-height': '100%',
|
||||
'background-color': '#FFF'
|
||||
});
|
||||
|
||||
setStreamHeight();
|
||||
setStreamHeight();
|
||||
|
||||
// Slide in stream
|
||||
stream.show('slide', {'direction': 'left'}, {'duration': 500, 'queue': false });
|
||||
|
||||
}
|
||||
}])
|
||||
// Slide in stream
|
||||
stream.show('slide', {
|
||||
'direction': 'left'
|
||||
}, {
|
||||
'duration': 500,
|
||||
'queue': false
|
||||
});
|
||||
|
||||
.factory('HideStream', [ 'LoadBreadCrumbs', function(LoadBreadCrumbs) {
|
||||
return function() {
|
||||
// Remove the stream widget
|
||||
|
||||
var stream = $('#stream-container');
|
||||
stream.hide('slide', {'direction': 'left'}, {'duration': 500, 'queue': false });
|
||||
|
||||
// Completely destroy the container so we don't experience random flashes of it later.
|
||||
// There was some sort of weirdness with the tab 'show' causing the stream to slide in when
|
||||
// a tab was clicked, after the stream had been hidden. Seemed like timing- wait long enough
|
||||
// before clicking a tab, and it would not happen.
|
||||
setTimeout( function() {
|
||||
stream.detach();
|
||||
stream.empty();
|
||||
stream.unbind();
|
||||
$('#tab-content-container').css({ 'min-height': 0 }); //let the parent height go back to normal
|
||||
}, 500);
|
||||
|
||||
LoadBreadCrumbs();
|
||||
}
|
||||
}])
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
.factory('StreamBreadCrumbs', ['$rootScope', '$location', function($rootScope, $location) {
|
||||
return function() {
|
||||
// Load the breadcrumbs array. We have to do things a bit different than Utilities.LoadBreadcrumbs.
|
||||
// Rather than botch that all up, we'll do our own thing here.
|
||||
$rootScope.breadcrumbs = [];
|
||||
var paths = $location.path().split('/');
|
||||
paths.splice(0,1);
|
||||
var path, title, i, j;
|
||||
for (i=0; i < paths.length; i++) {
|
||||
if (/^\d+/.test(paths[i])) {
|
||||
path='';
|
||||
title='';
|
||||
for (j=0; j <= i; j++) {
|
||||
path += '/' + paths[j];
|
||||
}
|
||||
for (j=0; j < $rootScope.crumbCache.length; j++) {
|
||||
if ($rootScope.crumbCache[j].path == path) {
|
||||
title = $rootScope.crumbCache[j].title;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!title) {
|
||||
title = paths[i - 1].substr(0,paths[i - 1].length - 1);
|
||||
title = title.charAt(0).toUpperCase() + title.slice(1);
|
||||
title = (title == 'Inventorie') ? 'Inventory' : title;
|
||||
}
|
||||
}
|
||||
else {
|
||||
path='';
|
||||
title='';
|
||||
if (i > 0) {
|
||||
for (j=0; j <= i; j++) {
|
||||
.factory('HideStream', ['LoadBreadCrumbs',
|
||||
function (LoadBreadCrumbs) {
|
||||
return function () {
|
||||
// Remove the stream widget
|
||||
|
||||
var stream = $('#stream-container');
|
||||
stream.hide('slide', {
|
||||
'direction': 'left'
|
||||
}, {
|
||||
'duration': 500,
|
||||
'queue': false
|
||||
});
|
||||
|
||||
// Completely destroy the container so we don't experience random flashes of it later.
|
||||
// There was some sort of weirdness with the tab 'show' causing the stream to slide in when
|
||||
// a tab was clicked, after the stream had been hidden. Seemed like timing- wait long enough
|
||||
// before clicking a tab, and it would not happen.
|
||||
setTimeout(function () {
|
||||
stream.detach();
|
||||
stream.empty();
|
||||
stream.unbind();
|
||||
$('#tab-content-container').css({
|
||||
'min-height': 0
|
||||
}); //let the parent height go back to normal
|
||||
}, 500);
|
||||
|
||||
LoadBreadCrumbs();
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
.factory('StreamBreadCrumbs', ['$rootScope', '$location',
|
||||
function ($rootScope, $location) {
|
||||
return function () {
|
||||
// Load the breadcrumbs array. We have to do things a bit different than Utilities.LoadBreadcrumbs.
|
||||
// Rather than botch that all up, we'll do our own thing here.
|
||||
$rootScope.breadcrumbs = [];
|
||||
var path, title, i, j, paths = $location.path().split('/');
|
||||
paths.splice(0, 1);
|
||||
for (i = 0; i < paths.length; i++) {
|
||||
if (/^\d+/.test(paths[i])) {
|
||||
path = '';
|
||||
title = '';
|
||||
for (j = 0; j <= i; j++) {
|
||||
path += '/' + paths[j];
|
||||
}
|
||||
for (j = 0; j < $rootScope.crumbCache.length; j++) {
|
||||
if ($rootScope.crumbCache[j].path === path) {
|
||||
title = $rootScope.crumbCache[j].title;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!title) {
|
||||
title = paths[i - 1].substr(0, paths[i - 1].length - 1);
|
||||
title = title.charAt(0).toUpperCase() + title.slice(1);
|
||||
title = (title === 'Inventorie') ? 'Inventory' : title;
|
||||
}
|
||||
} else {
|
||||
path = '';
|
||||
title = '';
|
||||
if (i > 0) {
|
||||
for (j = 0; j <= i; j++) {
|
||||
path += '/' + paths[j];
|
||||
}
|
||||
} else {
|
||||
path = '/' + paths[i];
|
||||
}
|
||||
title = paths[i];
|
||||
title = title.charAt(0).toUpperCase() + title.slice(1);
|
||||
}
|
||||
else {
|
||||
path = '/' + paths[i];
|
||||
}
|
||||
title = paths[i];
|
||||
title = title.charAt(0).toUpperCase() + title.slice(1);
|
||||
$rootScope.breadcrumbs.push({
|
||||
path: path,
|
||||
title: title,
|
||||
ngClick: "closeStream('" + path + "')"
|
||||
});
|
||||
}
|
||||
$rootScope.breadcrumbs.push({ path: path, title: title, ngClick: "closeStream('" + path + "')" });
|
||||
}
|
||||
}
|
||||
}])
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
.factory('FixUrl', [ function() {
|
||||
return function(u) {
|
||||
return u.replace(/\/api\/v1\//,'/#/');
|
||||
}
|
||||
}])
|
||||
.factory('FixUrl', [
|
||||
function () {
|
||||
return function (u) {
|
||||
return u.replace(/\/api\/v1\//, '/#/');
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
.factory('BuildUrl', [ function() {
|
||||
return function(obj) {
|
||||
var url = '/#/';
|
||||
switch(obj.base) {
|
||||
case 'group':
|
||||
case 'host':
|
||||
url += 'home/' + obj.base + 's/?id=' + obj.id;
|
||||
break;
|
||||
case 'inventory':
|
||||
url += 'inventories/' + obj.id + '/';
|
||||
break;
|
||||
default:
|
||||
url += obj.base + 's/' + obj.id + '/';
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('BuildDescription', ['FixUrl', 'BuildUrl', function(FixUrl, BuildUrl) {
|
||||
return function(activity) {
|
||||
|
||||
function stripDeleted(s) {
|
||||
return s.replace(/^_deleted_\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+\+\d+:\d+_/,'');
|
||||
.factory('BuildUrl', [
|
||||
function () {
|
||||
return function (obj) {
|
||||
var url = '/#/';
|
||||
switch (obj.base) {
|
||||
case 'group':
|
||||
case 'host':
|
||||
url += 'home/' + obj.base + 's/?id=' + obj.id;
|
||||
break;
|
||||
case 'inventory':
|
||||
url += 'inventories/' + obj.id + '/';
|
||||
break;
|
||||
default:
|
||||
url += obj.base + 's/' + obj.id + '/';
|
||||
}
|
||||
|
||||
var descr = '';
|
||||
var descr_nolink;
|
||||
descr += activity.operation;
|
||||
descr += (/e$/.test(activity.operation)) ? 'd ' : 'ed ';
|
||||
descr_nolink = descr;
|
||||
return url;
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
// labels
|
||||
var obj1 = activity.object1;
|
||||
var obj2 = activity.object2;
|
||||
|
||||
// objects
|
||||
var obj1_obj = (activity.summary_fields[obj1]) ? activity.summary_fields[obj1][0] : null;
|
||||
if (obj1 == obj2) {
|
||||
var obj2_obj = activity.summary_fields[obj1][1];
|
||||
}
|
||||
else if (activity.summary_fields[obj2]) {
|
||||
var obj2_obj = activity.summary_fields[obj2][0];
|
||||
}
|
||||
else {
|
||||
var obj2_obj = null;
|
||||
}
|
||||
|
||||
if (obj1 == 'user' || obj2 == 'user') {
|
||||
activity.summary_fields['user'][0].name = activity.summary_fields['user'][0].username;
|
||||
}
|
||||
|
||||
var name;
|
||||
if (obj2_obj && obj2_obj.name && !/^_delete/.test(obj2_obj.name)) {
|
||||
obj2_obj['base'] = obj2;
|
||||
descr += obj2 + ' <a href=\"' + BuildUrl(obj2_obj) + '\">'
|
||||
+ obj2_obj.name + '</a>' + ( (activity.operation == 'disassociate') ? ' from ' : ' to ' );
|
||||
descr_nolink += obj2 + ' ' + obj2_obj.name + ( (activity.operation == 'disassociate') ? ' from ' : ' to ' );
|
||||
}
|
||||
else if (obj2) {
|
||||
name = '';
|
||||
if (obj2_obj && obj2_obj.name) {
|
||||
name = ' ' + stripDeleted(obj2_obj.name);
|
||||
.factory('BuildDescription', ['FixUrl', 'BuildUrl',
|
||||
function (FixUrl, BuildUrl) {
|
||||
return function (activity) {
|
||||
|
||||
function stripDeleted(s) {
|
||||
return s.replace(/^_deleted_\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+\+\d+:\d+_/, '');
|
||||
}
|
||||
descr += obj2 + name + ( (activity.operation == 'disassociate') ? ' from ' : ' to ' );
|
||||
descr_nolink += obj2 + name + ( (activity.operation == 'disassociate') ? ' from ' : ' to ' );
|
||||
}
|
||||
if (obj1_obj && obj1_obj.name && !/^\_delete/.test(obj1_obj.name)) {
|
||||
obj1_obj['base'] = obj1;
|
||||
descr += obj1 + ' <a href=\"' + BuildUrl(obj1_obj) + '\">' + obj1_obj.name + '</a>';
|
||||
descr_nolink += obj1 + ' ' + obj1_obj.name;
|
||||
}
|
||||
else if (obj1) {
|
||||
name = '';
|
||||
var name_nolink = '';
|
||||
// find the name in changes, if needed
|
||||
if ( !(obj1_obj && obj1_obj.name) || obj1_obj && obj1_obj.name && /^_delete/.test(obj1_obj.name) ) {
|
||||
if (activity.changes && activity.changes.name) {
|
||||
if (typeof activity.changes.name == 'string') {
|
||||
name = ' ' + activity.changes.name;
|
||||
name_nolink = name;
|
||||
}
|
||||
else if (typeof activity.changes.name == 'object' && Array.isArray(activity.changes.name)) {
|
||||
name = ' ' + activity.changes.name[0];
|
||||
name_nolink = name;
|
||||
}
|
||||
}
|
||||
else if (obj1 == 'job' && obj1_obj && activity.changes && activity.changes.job_template) {
|
||||
// Hack for job activity where the template name is known
|
||||
if (activity.operation != 'delete') {
|
||||
obj1_obj['base'] = obj1;
|
||||
name = ' ' + '<a href=\"' + BuildUrl(obj1_obj) + '\">'+ obj1_obj.id + ' ' + activity.changes.job_template + '</a>';
|
||||
name_nolink = ' ' + obj1_obj.id + ' ' + activity.changes.job_template;
|
||||
}
|
||||
else {
|
||||
name = ' ' + obj1_obj.id + ' ' + activity.changes.job_template;
|
||||
name_nolink = name;
|
||||
}
|
||||
}
|
||||
else if (obj1 == 'job' && obj1_obj) {
|
||||
// Hack for job activity where template name not known
|
||||
if (activity.operation != 'delete') {
|
||||
obj1_obj['base'] = obj1;
|
||||
name = ' ' + '<a href=\"' + BuildUrl(obj1_obj) + '\">' + obj1_obj.id + '</a>';
|
||||
name_nolink = ' ' + obj1_obj.id;
|
||||
}
|
||||
else {
|
||||
name = ' ' + obj1_obj.id;
|
||||
name_nolink = name;
|
||||
}
|
||||
}
|
||||
|
||||
var descr, descr_nolink, obj1, obj2, obj1_obj, obj2_obj, name, name_nolink;
|
||||
|
||||
descr = activity.operation;
|
||||
descr += (/e$/.test(activity.operation)) ? 'd ' : 'ed ';
|
||||
descr_nolink = descr;
|
||||
|
||||
// labels
|
||||
obj1 = activity.object1;
|
||||
obj2 = activity.object2;
|
||||
|
||||
// objects
|
||||
obj1_obj = (activity.summary_fields[obj1]) ? activity.summary_fields[obj1][0] : null;
|
||||
if (obj1 === obj2) {
|
||||
obj2_obj = activity.summary_fields[obj1][1];
|
||||
} else if (activity.summary_fields[obj2]) {
|
||||
obj2_obj = activity.summary_fields[obj2][0];
|
||||
} else {
|
||||
obj2_obj = null;
|
||||
}
|
||||
else if (obj1_obj && obj1_obj.name) {
|
||||
name = ' ' + stripDeleted(obj1_obj.name);
|
||||
name_nolink = name;
|
||||
|
||||
if (obj1 === 'user' || obj2 === 'user') {
|
||||
activity.summary_fields.user[0].name = activity.summary_fields.user[0].username;
|
||||
}
|
||||
descr += obj1 + name;
|
||||
descr_nolink += obj1 + name_nolink;
|
||||
}
|
||||
activity['description'] = descr;
|
||||
activity['description_nolink'] = descr_nolink;
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('ShowDetail', ['$rootScope', 'Rest', 'Alert', 'GenerateForm', 'ProcessErrors', 'GetBasePath', 'FormatDate',
|
||||
'ActivityDetailForm', 'Empty', 'Find',
|
||||
function($rootScope, Rest, Alert, GenerateForm, ProcessErrors, GetBasePath, FormatDate, ActivityDetailForm, Empty, Find) {
|
||||
return function(params) {
|
||||
|
||||
var activity_id = params.activity_id;
|
||||
var parent_scope = params.scope;
|
||||
|
||||
var generator = GenerateForm;
|
||||
var form = ActivityDetailForm;
|
||||
var activity = Find({list: parent_scope.activities, key: 'id', val: activity_id });
|
||||
|
||||
if (activity) {
|
||||
// Setup changes field
|
||||
activity['changes_stringified'] = JSON.stringify(activity['changes'], null, '\t');
|
||||
var n = activity['changes_stringified'].match(/\n/g);
|
||||
var rows = (n) ? n.length : 1;
|
||||
rows = (rows < 1) ? 3 : 10;
|
||||
form.fields['changes'].rows = 10;
|
||||
|
||||
// Load the form
|
||||
var scope = generator.inject(form, { mode: 'edit', modal: true, related: false });
|
||||
scope['changes'] = activity['changes_stringified'];
|
||||
scope['user'] = ( (activity.summary_fields.actor) ? activity.summary_fields.actor.username : 'system' ) +
|
||||
' on ' + FormatDate(new Date(activity['timestamp']));
|
||||
scope['operation'] = activity['description_nolink'];
|
||||
|
||||
scope.formModalAction = function() {
|
||||
$('#form-modal').modal("hide");
|
||||
if (obj2_obj && obj2_obj.name && !/^_delete/.test(obj2_obj.name)) {
|
||||
obj2_obj.base = obj2;
|
||||
descr += obj2 + ' <a href=\"' + BuildUrl(obj2_obj) + '\">' + obj2_obj.name + '</a>' + ((activity.operation === 'disassociate') ? ' from ' : ' to ');
|
||||
descr_nolink += obj2 + ' ' + obj2_obj.name + ((activity.operation === 'disassociate') ? ' from ' : ' to ');
|
||||
} else if (obj2) {
|
||||
name = '';
|
||||
if (obj2_obj && obj2_obj.name) {
|
||||
name = ' ' + stripDeleted(obj2_obj.name);
|
||||
}
|
||||
|
||||
$('#form-modal').on('show.bs.modal', function (e) {
|
||||
$('#form-modal-body').css({
|
||||
width:'auto', //probably not needed
|
||||
height:'auto', //probably not needed
|
||||
'max-height':'100%'
|
||||
descr += obj2 + name + ((activity.operation === 'disassociate') ? ' from ' : ' to ');
|
||||
descr_nolink += obj2 + name + ((activity.operation === 'disassociate') ? ' from ' : ' to ');
|
||||
}
|
||||
if (obj1_obj && obj1_obj.name && !/^\_delete/.test(obj1_obj.name)) {
|
||||
obj1_obj.base = obj1;
|
||||
descr += obj1 + ' <a href=\"' + BuildUrl(obj1_obj) + '\">' + obj1_obj.name + '</a>';
|
||||
descr_nolink += obj1 + ' ' + obj1_obj.name;
|
||||
} else if (obj1) {
|
||||
name = '';
|
||||
name_nolink = '';
|
||||
// find the name in changes, if needed
|
||||
if (!(obj1_obj && obj1_obj.name) || obj1_obj && obj1_obj.name && /^_delete/.test(obj1_obj.name)) {
|
||||
if (activity.changes && activity.changes.name) {
|
||||
if (typeof activity.changes.name === 'string') {
|
||||
name = ' ' + activity.changes.name;
|
||||
name_nolink = name;
|
||||
} else if (typeof activity.changes.name === 'object' && Array.isArray(activity.changes.name)) {
|
||||
name = ' ' + activity.changes.name[0];
|
||||
name_nolink = name;
|
||||
}
|
||||
} else if (obj1 === 'job' && obj1_obj && activity.changes && activity.changes.job_template) {
|
||||
// Hack for job activity where the template name is known
|
||||
if (activity.operation !== 'delete') {
|
||||
obj1_obj.base = obj1;
|
||||
name = ' ' + '<a href=\"' + BuildUrl(obj1_obj) + '\">' + obj1_obj.id + ' ' + activity.changes.job_template + '</a>';
|
||||
name_nolink = ' ' + obj1_obj.id + ' ' + activity.changes.job_template;
|
||||
} else {
|
||||
name = ' ' + obj1_obj.id + ' ' + activity.changes.job_template;
|
||||
name_nolink = name;
|
||||
}
|
||||
} else if (obj1 === 'job' && obj1_obj) {
|
||||
// Hack for job activity where template name not known
|
||||
if (activity.operation !== 'delete') {
|
||||
obj1_obj.base = obj1;
|
||||
name = ' ' + '<a href=\"' + BuildUrl(obj1_obj) + '\">' + obj1_obj.id + '</a>';
|
||||
name_nolink = ' ' + obj1_obj.id;
|
||||
} else {
|
||||
name = ' ' + obj1_obj.id;
|
||||
name_nolink = name;
|
||||
}
|
||||
}
|
||||
} else if (obj1_obj && obj1_obj.name) {
|
||||
name = ' ' + stripDeleted(obj1_obj.name);
|
||||
name_nolink = name;
|
||||
}
|
||||
descr += obj1 + name;
|
||||
descr_nolink += obj1 + name_nolink;
|
||||
}
|
||||
activity.description = descr;
|
||||
activity.description_nolink = descr_nolink;
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
.factory('ShowDetail', ['$rootScope', 'Rest', 'Alert', 'GenerateForm', 'ProcessErrors', 'GetBasePath', 'FormatDate',
|
||||
'ActivityDetailForm', 'Empty', 'Find',
|
||||
function ($rootScope, Rest, Alert, GenerateForm, ProcessErrors, GetBasePath, FormatDate, ActivityDetailForm, Empty, Find) {
|
||||
return function (params) {
|
||||
|
||||
var activity_id = params.activity_id,
|
||||
parent_scope = params.scope,
|
||||
generator = GenerateForm,
|
||||
form = ActivityDetailForm,
|
||||
activity = Find({ list: parent_scope.activities, key: 'id', val: activity_id }),
|
||||
n, rows, scope;
|
||||
|
||||
if (activity) {
|
||||
// Setup changes field
|
||||
activity.changes_stringified = JSON.stringify(activity.changes, null, '\t');
|
||||
n = activity.changes_stringified.match(/\n/g);
|
||||
rows = (n) ? n.length : 1;
|
||||
rows = (rows < 1) ? 3 : 10;
|
||||
form.fields.changes.rows = 10;
|
||||
|
||||
// Load the form
|
||||
scope = generator.inject(form, { mode: 'edit', modal: true, related: false });
|
||||
scope.changes = activity.changes_stringified;
|
||||
scope.user = ((activity.summary_fields.actor) ? activity.summary_fields.actor.username : 'system') +
|
||||
' on ' + FormatDate(new Date(activity.timestamps));
|
||||
scope.operation = activity.description_nolink;
|
||||
|
||||
scope.formModalAction = function () {
|
||||
$('#form-modal').modal("hide");
|
||||
};
|
||||
|
||||
$('#form-modal').on('show.bs.modal', function () {
|
||||
$('#form-modal-body').css({
|
||||
width: 'auto', //probably not needed
|
||||
height: 'auto', //probably not needed
|
||||
'max-height': '100%'
|
||||
});
|
||||
});
|
||||
|
||||
scope.formModalActionLabel = 'OK';
|
||||
scope.formModalCancelShow = false;
|
||||
scope.formModalInfo = false;
|
||||
scope.formModalHeader = "Event " + activity.id;
|
||||
|
||||
if (!scope.$$phase) {
|
||||
scope.$digest();
|
||||
scope.formModalActionLabel = 'OK';
|
||||
scope.formModalCancelShow = false;
|
||||
scope.formModalInfo = false;
|
||||
scope.formModalHeader = "Event " + activity.id;
|
||||
|
||||
if (!scope.$$phase) {
|
||||
scope.$digest();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('Stream', ['$rootScope', '$location', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', 'StreamList', 'SearchInit',
|
||||
'PaginateInit', 'GenerateList', 'FormatDate', 'ShowStream', 'HideStream', 'BuildDescription', 'FixUrl', 'BuildUrl',
|
||||
'ShowDetail', 'StreamBreadCrumbs', 'setStreamHeight', 'Find', 'Store',
|
||||
function($rootScope, $location, Rest, GetBasePath, ProcessErrors, Wait, StreamList, SearchInit, PaginateInit, GenerateList,
|
||||
.factory('Stream', ['$rootScope', '$location', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', 'StreamList', 'SearchInit',
|
||||
'PaginateInit', 'GenerateList', 'FormatDate', 'ShowStream', 'HideStream', 'BuildDescription', 'FixUrl', 'BuildUrl',
|
||||
'ShowDetail', 'StreamBreadCrumbs', 'setStreamHeight', 'Find', 'Store',
|
||||
function ($rootScope, $location, Rest, GetBasePath, ProcessErrors, Wait, StreamList, SearchInit, PaginateInit, GenerateList,
|
||||
FormatDate, ShowStream, HideStream, BuildDescription, FixUrl, BuildUrl, ShowDetail, StreamBreadCrumbs, setStreamHeight,
|
||||
Find, Store) {
|
||||
return function(params) {
|
||||
|
||||
var list = StreamList;
|
||||
var defaultUrl = GetBasePath('activity_stream');
|
||||
var view = GenerateList;
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
var parent_scope = params.scope;
|
||||
return function (params) {
|
||||
|
||||
// Hang onto current search params
|
||||
var PreviousSearchParams = Store('CurrentSearchParams');
|
||||
var list = StreamList,
|
||||
defaultUrl = GetBasePath('activity_stream'),
|
||||
view = GenerateList,
|
||||
base = $location.path().replace(/^\//, '').split('/')[0],
|
||||
parent_scope = params.scope,
|
||||
PreviousSearchParams = Store('CurrentSearchParams'),
|
||||
inventory_name = (params && params.inventory_name) ? params.inventory_name : null,
|
||||
url = (params && params.url) ? params.url : null,
|
||||
type, paths, itm, scope;
|
||||
|
||||
// pass in an inventory name to fix breadcrumb display
|
||||
var inventory_name = (params && params.inventory_name) ? params.inventory_name : null;
|
||||
$rootScope.flashMessage = null;
|
||||
|
||||
// url will override the attempt to compute an activity_stream query
|
||||
var url = (params && params.url) ? params.url : null;
|
||||
|
||||
$rootScope.flashMessage = null;
|
||||
|
||||
if (url) {
|
||||
defaultUrl = url;
|
||||
}
|
||||
else {
|
||||
if ($location.path() !== '/home') {
|
||||
// Restrict what we're looking at based on the path
|
||||
var type = (base == 'inventories') ? 'inventory' : base.replace(/s$/,'');
|
||||
var paths = $location.path().split('/');
|
||||
paths.splice(0,1);
|
||||
if (paths.length > 1 && /^\d+/.test(paths[paths.length - 1])) {
|
||||
type = paths[paths.length - 2];
|
||||
type = (type == 'inventories') ? 'inventory' : type.replace(/s$/,'');
|
||||
//defaultUrl += '?object1=' + type + '&object1__id=' +
|
||||
defaultUrl += '?' + type + '__id=' + paths[paths.length - 1];
|
||||
}
|
||||
else if (paths.length > 1) {
|
||||
type = paths[paths.length - 1];
|
||||
type = (type == 'inventories') ? 'inventory' : type.replace(/s$/,'');
|
||||
defaultUrl += '?or__object1=' + type + '&or__object2=' + type;
|
||||
}
|
||||
else {
|
||||
defaultUrl += '?or__object1=' + type + '&or__object2=' + type;
|
||||
if (url) {
|
||||
defaultUrl = url;
|
||||
} else {
|
||||
if ($location.path() !== '/home') {
|
||||
// Restrict what we're looking at based on the path
|
||||
type = (base === 'inventories') ? 'inventory' : base.replace(/s$/, '');
|
||||
paths = $location.path().split('/');
|
||||
paths.splice(0, 1);
|
||||
if (paths.length > 1 && /^\d+/.test(paths[paths.length - 1])) {
|
||||
type = paths[paths.length - 2];
|
||||
type = (type === 'inventories') ? 'inventory' : type.replace(/s$/, '');
|
||||
//defaultUrl += '?object1=' + type + '&object1__id=' +
|
||||
defaultUrl += '?' + type + '__id=' + paths[paths.length - 1];
|
||||
} else if (paths.length > 1) {
|
||||
type = paths[paths.length - 1];
|
||||
type = (type === 'inventories') ? 'inventory' : type.replace(/s$/, '');
|
||||
defaultUrl += '?or__object1=' + type + '&or__object2=' + type;
|
||||
} else {
|
||||
defaultUrl += '?or__object1=' + type + '&or__object2=' + type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add a container for the stream widget
|
||||
$('#tab-content-container').append("<div id=\"stream-container\"><div id=\"stream-content\"></div></div><!-- Stream widget -->");
|
||||
|
||||
StreamBreadCrumbs();
|
||||
// Add a container for the stream widget
|
||||
$('#tab-content-container').append("<div id=\"stream-container\"><div id=\"stream-content\"></div></div><!-- Stream widget -->");
|
||||
|
||||
// Fix inventory name. The way we're doing breadcrumbs doesn't support bind variables.
|
||||
if (inventory_name) {
|
||||
var itm = Find({ list: $rootScope.breadcrumbs, key: 'title', val: '{{ inventory_name }}' });
|
||||
if (itm) {
|
||||
itm.title = inventory_name;
|
||||
StreamBreadCrumbs();
|
||||
|
||||
// Fix inventory name. The way we're doing breadcrumbs doesn't support bind variables.
|
||||
if (inventory_name) {
|
||||
itm = Find({ list: $rootScope.breadcrumbs, key: 'title', val: '{{ inventory_name }}' });
|
||||
if (itm) {
|
||||
itm.title = inventory_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShowStream();
|
||||
|
||||
// Generate the list
|
||||
var scope = view.inject(list, {
|
||||
mode: 'edit',
|
||||
id: 'stream-content',
|
||||
searchSize: 'col-lg-3',
|
||||
secondWidget: true,
|
||||
activityStream: true
|
||||
ShowStream();
|
||||
|
||||
// Generate the list
|
||||
scope = view.inject(list, { mode: 'edit', id: 'stream-content', searchSize: 'col-lg-3', secondWidget: true, activityStream: true });
|
||||
|
||||
// descriptive title describing what AS is showing
|
||||
scope.streamTitle = (params && params.title) ? params.title : null;
|
||||
|
||||
scope.closeStream = function (inUrl) {
|
||||
HideStream();
|
||||
if (scope.searchCleanup) {
|
||||
scope.searchCleanup();
|
||||
}
|
||||
// Restore prior search state
|
||||
if (PreviousSearchParams) {
|
||||
SearchInit({
|
||||
scope: parent_scope,
|
||||
set: PreviousSearchParams.set,
|
||||
list: PreviousSearchParams.list,
|
||||
url: PreviousSearchParams.defaultUrl,
|
||||
iterator: PreviousSearchParams.iterator,
|
||||
sort_order: PreviousSearchParams.sort_order,
|
||||
setWidgets: false
|
||||
});
|
||||
}
|
||||
if (inUrl) {
|
||||
$location.path(inUrl);
|
||||
}
|
||||
};
|
||||
|
||||
scope.refreshStream = function () {
|
||||
scope.search(list.iterator);
|
||||
};
|
||||
|
||||
scope.showDetail = function (id) {
|
||||
ShowDetail({
|
||||
scope: scope,
|
||||
activity_id: id
|
||||
});
|
||||
};
|
||||
|
||||
if (scope.removeStreamPostRefresh) {
|
||||
scope.removeStreamPostRefresh();
|
||||
}
|
||||
scope.removeStreamPostRefresh = scope.$on('PostRefresh', function () {
|
||||
var i, cDate, href, deleted, obj1, obj2;
|
||||
for (i = 0; i < scope.activities.length; i++) {
|
||||
// Convert event_time date to local time zone
|
||||
cDate = new Date(scope.activities[i].timestamp);
|
||||
scope.activities[i].timestamp = FormatDate(cDate);
|
||||
|
||||
if (scope.activities[i].summary_fields.actor) {
|
||||
scope.activities[i].user = "<a href=\"/#/users/" + scope.activities[i].summary_fields.actor.id + "\">" +
|
||||
scope.activities[i].summary_fields.actor.username + "</a>";
|
||||
} else {
|
||||
scope.activities[i].user = 'system';
|
||||
}
|
||||
|
||||
// Objects
|
||||
deleted = /^\_delete/;
|
||||
obj1 = scope.activities[i].object1;
|
||||
obj2 = scope.activities[i].object2;
|
||||
if (obj1 && scope.activities[i].summary_fields[obj1] && scope.activities[i].summary_fields[obj1].name) {
|
||||
if (!deleted.test(scope.activities[i].summary_fields[obj1].name)) {
|
||||
href = BuildUrl(scope.activities[i].summary_fields.object1);
|
||||
scope.activities[i].objects = "<a href=\"" + href + "\">" + scope.activities[i].summary_fields[obj1].name + "</a>";
|
||||
} else {
|
||||
scope.activities[i].objects = scope.activities[i].summary_fields[obj1].name;
|
||||
}
|
||||
} else if (scope.activities[i].object1) {
|
||||
scope.activities[i].objects = scope.activities[i].object1;
|
||||
}
|
||||
if (obj2 && scope.activities[i].summary_fields[obj2] && scope.activities[i].summary_fields[obj2].name) {
|
||||
if (!deleted.test(scope.activities[i].summary_fields.object2.name)) {
|
||||
href = BuildUrl(scope.activities[i].summary_fields.object2);
|
||||
scope.activities[i].objects += ", <a href=\"" + href + "\">" + scope.activities[i].summary_fields[obj2].name + "</a>";
|
||||
} else {
|
||||
scope.activities[i].objects += "," + scope.activities[i].summary_fields[obj2].name;
|
||||
}
|
||||
} else if (scope.activities[i].object2) {
|
||||
scope.activities[i].objects += ", " + scope.activities[i].object2;
|
||||
}
|
||||
|
||||
BuildDescription(scope.activities[i]);
|
||||
|
||||
}
|
||||
// Give ng-repeate a chance to show the data before adjusting the page size.
|
||||
setTimeout(function () {
|
||||
setStreamHeight();
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// descriptive title describing what AS is showing
|
||||
scope.streamTitle = (params && params.title) ? params.title : null;
|
||||
|
||||
scope.closeStream = function(inUrl) {
|
||||
HideStream();
|
||||
if (scope.searchCleanup) {
|
||||
scope.searchCleanup();
|
||||
}
|
||||
// Restore prior search state
|
||||
if (PreviousSearchParams) {
|
||||
SearchInit({
|
||||
scope: parent_scope,
|
||||
set: PreviousSearchParams.set,
|
||||
list: PreviousSearchParams.list,
|
||||
url: PreviousSearchParams.defaultUrl,
|
||||
iterator: PreviousSearchParams.iterator,
|
||||
sort_order: PreviousSearchParams.sort_order,
|
||||
setWidgets: false });
|
||||
}
|
||||
if (inUrl) {
|
||||
$location.path(inUrl);
|
||||
}
|
||||
}
|
||||
|
||||
scope.refreshStream = function() {
|
||||
// Initialize search and paginate pieces and load data
|
||||
SearchInit({
|
||||
scope: scope,
|
||||
set: list.name,
|
||||
list: list,
|
||||
url: defaultUrl
|
||||
});
|
||||
PaginateInit({
|
||||
scope: scope,
|
||||
list: list,
|
||||
url: defaultUrl
|
||||
});
|
||||
scope.search(list.iterator);
|
||||
}
|
||||
|
||||
scope.showDetail = function(id) {
|
||||
ShowDetail({ scope: scope, activity_id: id });
|
||||
}
|
||||
|
||||
if (scope.removeStreamPostRefresh) {
|
||||
scope.removeStreamPostRefresh();
|
||||
}
|
||||
scope.removeStreamPostRefresh = scope.$on('PostRefresh', function() {
|
||||
var cDate, href, deleted, obj1, obj2;
|
||||
for (var i=0; i < scope['activities'].length; i++) {
|
||||
// Convert event_time date to local time zone
|
||||
cDate = new Date(scope['activities'][i].timestamp);
|
||||
scope['activities'][i].timestamp = FormatDate(cDate);
|
||||
|
||||
if (scope['activities'][i]['summary_fields']['actor']) {
|
||||
scope['activities'][i]['user'] = "<a href=\"/#/users/" + scope['activities'][i]['summary_fields']['actor']['id'] + "\">" +
|
||||
scope['activities'][i]['summary_fields']['actor']['username'] + "</a>";
|
||||
}
|
||||
else {
|
||||
scope['activities'][i]['user'] = 'system';
|
||||
}
|
||||
|
||||
// Objects
|
||||
deleted = /^\_delete/;
|
||||
obj1 = scope['activities'][i].object1;
|
||||
obj2 = scope['activities'][i].object2;
|
||||
if ( obj1 && scope['activities'][i].summary_fields[obj1] && scope['activities'][i].summary_fields[obj1].name) {
|
||||
if ( !deleted.test(scope['activities'][i].summary_fields[obj1].name) ) {
|
||||
href = BuildUrl(scope['activities'][i].summary_fields.object1);
|
||||
scope['activities'][i].objects = "<a href=\"" + href + "\">" + scope['activities'][i].summary_fields[obj1].name + "</a>";
|
||||
}
|
||||
else {
|
||||
scope['activities'][i].objects = scope['activities'][i].summary_fields[obj1].name;
|
||||
}
|
||||
}
|
||||
else if (scope['activities'][i].object1) {
|
||||
scope['activities'][i].objects = scope['activities'][i].object1;
|
||||
}
|
||||
if (obj2 && scope['activities'][i].summary_fields[obj2] && scope['activities'][i].summary_fields[obj2].name) {
|
||||
if ( !deleted.test(scope['activities'][i].summary_fields.object2.name) ) {
|
||||
href = BuildUrl(scope['activities'][i].summary_fields.object2);
|
||||
scope['activities'][i].objects += ", <a href=\"" + href + "\">" + scope['activities'][i].summary_fields[obj2].name + "</a>";
|
||||
}
|
||||
else {
|
||||
scope['activities'][i].objects += "," + scope['activities'][i].summary_fields[obj2].name;
|
||||
}
|
||||
}
|
||||
else if (scope['activities'][i].object2) {
|
||||
scope['activities'][i].objects += ", " + scope['activities'][i].object2;
|
||||
}
|
||||
|
||||
BuildDescription(scope['activities'][i]);
|
||||
|
||||
}
|
||||
// Give ng-repeate a chance to show the data before adjusting the page size.
|
||||
setTimeout(function() { setStreamHeight(); }, 500);
|
||||
});
|
||||
|
||||
// Initialize search and paginate pieces and load data
|
||||
SearchInit({ scope: scope, set: list.name, list: list, url: defaultUrl });
|
||||
PaginateInit({ scope: scope, list: list, url: defaultUrl });
|
||||
scope.search(list.iterator);
|
||||
|
||||
}
|
||||
}]);
|
||||
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -4,129 +4,138 @@
|
||||
* AuthService.js
|
||||
*
|
||||
* User authentication functions
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('AuthService', ['ngCookies', 'Utilities'])
|
||||
|
||||
|
||||
.factory('Authorization', ['$http', '$rootScope', '$location', '$cookieStore', 'GetBasePath',
|
||||
function($http, $rootScope, $location, $cookieStore, GetBasePath) {
|
||||
return {
|
||||
setToken: function(token, expires) {
|
||||
// set the session cookie
|
||||
$cookieStore.remove('token');
|
||||
$cookieStore.remove('token_expires');
|
||||
$cookieStore.remove('userLoggedIn');
|
||||
$cookieStore.put('token', token);
|
||||
$cookieStore.put('token_expires', expires);
|
||||
$cookieStore.put('userLoggedIn', true);
|
||||
$cookieStore.put('sessionExpired', false);
|
||||
$rootScope.token = token;
|
||||
$rootScope.userLoggedIn = true;
|
||||
$rootScope.token_expires = expires;
|
||||
$rootScope.sessionExpired = false;
|
||||
},
|
||||
function ($http, $rootScope, $location, $cookieStore, GetBasePath) {
|
||||
return {
|
||||
setToken: function (token, expires) {
|
||||
// set the session cookie
|
||||
$cookieStore.remove('token');
|
||||
$cookieStore.remove('token_expires');
|
||||
$cookieStore.remove('userLoggedIn');
|
||||
$cookieStore.put('token', token);
|
||||
$cookieStore.put('token_expires', expires);
|
||||
$cookieStore.put('userLoggedIn', true);
|
||||
$cookieStore.put('sessionExpired', false);
|
||||
$rootScope.token = token;
|
||||
$rootScope.userLoggedIn = true;
|
||||
$rootScope.token_expires = expires;
|
||||
$rootScope.sessionExpired = false;
|
||||
},
|
||||
|
||||
isUserLoggedIn: function() {
|
||||
if ($rootScope.userLoggedIn === undefined) {
|
||||
// Browser refresh may have occurred
|
||||
$rootScope.userLoggedIn = $cookieStore.get('userLoggedIn');
|
||||
$rootScope.sessionExpired = $cookieStore.get('sessionExpired');
|
||||
}
|
||||
return $rootScope.userLoggedIn;
|
||||
},
|
||||
|
||||
getToken: function() {
|
||||
return ($rootScope.token) ? $rootScope.token : $cookieStore.get('token');
|
||||
},
|
||||
|
||||
retrieveToken: function(username, password) {
|
||||
return $http({ method: 'POST', url: GetBasePath('authtoken'),
|
||||
data: {"username": username, "password": password} });
|
||||
},
|
||||
|
||||
logout: function() {
|
||||
// the following puts our primary scope up for garbage collection, which
|
||||
// should prevent content flash from the prior user.
|
||||
var scope = angular.element(document.getElementById('main-view')).scope();
|
||||
scope.$destroy();
|
||||
$rootScope.$destroy();
|
||||
$cookieStore.remove('accordions');
|
||||
$cookieStore.remove('token');
|
||||
$cookieStore.remove('token_expires');
|
||||
$cookieStore.remove('current_user');
|
||||
$cookieStore.remove('lastPath');
|
||||
$cookieStore.put('userLoggedIn', false);
|
||||
$cookieStore.put('sessionExpired', false);
|
||||
$cookieStore.remove('lastPath', '/home');
|
||||
$rootScope.current_user = {};
|
||||
$rootScope.license_tested = undefined;
|
||||
$rootScope.userLoggedIn = false;
|
||||
$rootScope.sessionExpired = false;
|
||||
$rootScope.token = null;
|
||||
$rootScope.token_expires = null;
|
||||
$rootScope.lastPath = '/home';
|
||||
},
|
||||
|
||||
getLicense: function() {
|
||||
return $http({
|
||||
method: 'GET',
|
||||
url: GetBasePath('config'),
|
||||
headers: { 'Authorization': 'Token ' + this.getToken() }
|
||||
});
|
||||
},
|
||||
|
||||
setLicense: function(license) {
|
||||
license.tested = false;
|
||||
$cookieStore.put('license', license);
|
||||
},
|
||||
|
||||
licenseTested: function() {
|
||||
var license, result;
|
||||
if ($rootScope.license_tested !== undefined) {
|
||||
result = $rootScope.license_tested;
|
||||
}
|
||||
else {
|
||||
license = $cookieStore.get('license');
|
||||
if (license && license.tested !== undefined) {
|
||||
result = license.tested;
|
||||
isUserLoggedIn: function () {
|
||||
if ($rootScope.userLoggedIn === undefined) {
|
||||
// Browser refresh may have occurred
|
||||
$rootScope.userLoggedIn = $cookieStore.get('userLoggedIn');
|
||||
$rootScope.sessionExpired = $cookieStore.get('sessionExpired');
|
||||
}
|
||||
else {
|
||||
result = false;
|
||||
return $rootScope.userLoggedIn;
|
||||
},
|
||||
|
||||
getToken: function () {
|
||||
return ($rootScope.token) ? $rootScope.token : $cookieStore.get('token');
|
||||
},
|
||||
|
||||
retrieveToken: function (username, password) {
|
||||
return $http({
|
||||
method: 'POST',
|
||||
url: GetBasePath('authtoken'),
|
||||
data: {
|
||||
"username": username,
|
||||
"password": password
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
logout: function () {
|
||||
// the following puts our primary scope up for garbage collection, which
|
||||
// should prevent content flash from the prior user.
|
||||
var scope = angular.element(document.getElementById('main-view')).scope();
|
||||
scope.$destroy();
|
||||
$rootScope.$destroy();
|
||||
$cookieStore.remove('accordions');
|
||||
$cookieStore.remove('token');
|
||||
$cookieStore.remove('token_expires');
|
||||
$cookieStore.remove('current_user');
|
||||
$cookieStore.remove('lastPath');
|
||||
$cookieStore.put('userLoggedIn', false);
|
||||
$cookieStore.put('sessionExpired', false);
|
||||
$cookieStore.remove('lastPath', '/home');
|
||||
$rootScope.current_user = {};
|
||||
$rootScope.license_tested = undefined;
|
||||
$rootScope.userLoggedIn = false;
|
||||
$rootScope.sessionExpired = false;
|
||||
$rootScope.token = null;
|
||||
$rootScope.token_expires = null;
|
||||
$rootScope.lastPath = '/home';
|
||||
},
|
||||
|
||||
getLicense: function () {
|
||||
return $http({
|
||||
method: 'GET',
|
||||
url: GetBasePath('config'),
|
||||
headers: {
|
||||
'Authorization': 'Token ' + this.getToken()
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setLicense: function (license) {
|
||||
license.tested = false;
|
||||
$cookieStore.put('license', license);
|
||||
},
|
||||
|
||||
licenseTested: function () {
|
||||
var license, result;
|
||||
if ($rootScope.license_tested !== undefined) {
|
||||
result = $rootScope.license_tested;
|
||||
} else {
|
||||
license = $cookieStore.get('license');
|
||||
if (license && license.tested !== undefined) {
|
||||
result = license.tested;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
getUser: function () {
|
||||
return $http({
|
||||
method: 'GET',
|
||||
url: '/api/v1/me/',
|
||||
headers: {
|
||||
'Authorization': 'Token ' + this.getToken()
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setUserInfo: function (response) {
|
||||
// store the response values in $rootScope so we can get to them later
|
||||
$rootScope.current_user = response.results[0];
|
||||
$cookieStore.put('current_user', response.results[0]); //keep in session cookie in the event of browser refresh
|
||||
},
|
||||
|
||||
restoreUserInfo: function () {
|
||||
$rootScope.current_user = $cookieStore.get('current_user');
|
||||
},
|
||||
|
||||
getUserInfo: function (key) {
|
||||
// Access values returned from the Me API call
|
||||
var cu;
|
||||
if ($rootScope.current_user) {
|
||||
return $rootScope.current_user[key];
|
||||
}
|
||||
this.restoreUserInfo();
|
||||
cu = $cookieStore.get('current_user');
|
||||
return cu[key];
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
getUser: function() {
|
||||
return $http({
|
||||
method: 'GET',
|
||||
url: '/api/v1/me/',
|
||||
headers: { 'Authorization': 'Token ' + this.getToken() }
|
||||
});
|
||||
},
|
||||
|
||||
setUserInfo: function(response) {
|
||||
// store the response values in $rootScope so we can get to them later
|
||||
$rootScope.current_user = response.results[0];
|
||||
$cookieStore.put('current_user', response.results[0]); //keep in session cookie in the event of browser refresh
|
||||
},
|
||||
|
||||
restoreUserInfo: function() {
|
||||
$rootScope.current_user = $cookieStore.get('current_user');
|
||||
},
|
||||
|
||||
getUserInfo: function(key) {
|
||||
// Access values returned from the Me API call
|
||||
var cu;
|
||||
if ($rootScope.current_user ) {
|
||||
return $rootScope.current_user[key];
|
||||
}
|
||||
this.restoreUserInfo();
|
||||
cu = $cookieStore.get('current_user');
|
||||
return cu[key];
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
/************************************
|
||||
*
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
@ -8,86 +7,104 @@
|
||||
* Build data for the tree selector table used on inventory detail page.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'PromptDialog'])
|
||||
|
||||
.factory('SortNodes', [ function() {
|
||||
return function(data) {
|
||||
|
||||
.factory('SortNodes', [
|
||||
function () {
|
||||
return function (data) {
|
||||
//Sort nodes by name
|
||||
var names = [];
|
||||
var newData = [];
|
||||
for (var i=0; i < data.length; i++) {
|
||||
var i, j, names = [], newData = [];
|
||||
for (i = 0; i < data.length; i++) {
|
||||
names.push(data[i].name);
|
||||
}
|
||||
names.sort();
|
||||
for (var j=0; j < names.length; j++) {
|
||||
for (i=0; i < data.length; i++) {
|
||||
if (data[i].name == names[j]) {
|
||||
newData.push(data[i]);
|
||||
for (j = 0; j < names.length; j++) {
|
||||
for (i = 0; i < data.length; i++) {
|
||||
if (data[i].name === names[j]) {
|
||||
newData.push(data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newData;
|
||||
}
|
||||
}])
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
.factory('BuildTree', ['Rest', 'GetBasePath', 'ProcessErrors', 'SortNodes', 'Wait', 'GetSyncStatusMsg', 'GetHostsStatusMsg',
|
||||
function (Rest, GetBasePath, ProcessErrors, SortNodes, Wait, GetSyncStatusMsg, GetHostsStatusMsg) {
|
||||
return function (params) {
|
||||
|
||||
var inventory_id = params.inventory_id,
|
||||
scope = params.scope,
|
||||
refresh = params.refresh,
|
||||
emit = params.emit,
|
||||
new_group_id = params.new_group_id,
|
||||
groups = [],
|
||||
id = 1;
|
||||
|
||||
.factory('BuildTree', ['Rest', 'GetBasePath', 'ProcessErrors', 'SortNodes', 'Wait', 'GetSyncStatusMsg', 'GetHostsStatusMsg',
|
||||
function(Rest, GetBasePath, ProcessErrors, SortNodes, Wait, GetSyncStatusMsg, GetHostsStatusMsg) {
|
||||
return function(params) {
|
||||
|
||||
var inventory_id = params.inventory_id;
|
||||
var scope = params.scope;
|
||||
var refresh = params.refresh;
|
||||
var emit = params.emit;
|
||||
var new_group_id = params.new_group_id;
|
||||
var groups = [];
|
||||
var id = 1;
|
||||
|
||||
function buildAllHosts(tree_data) {
|
||||
// Start our tree object with All Hosts
|
||||
var children = [];
|
||||
var sorted = SortNodes(tree_data);
|
||||
for (var j=0; j < sorted.length; j++) {
|
||||
children.push(sorted[j].id);
|
||||
}
|
||||
var all_hosts = {
|
||||
name: 'All Hosts', id: 1, group_id: null, parent: 0, description: '', show: true, ngicon: null,
|
||||
has_children: false, related: {}, selected_class: '', show_failures: false, isDraggable: false,
|
||||
isDroppable: true, children: children };
|
||||
groups.push(all_hosts);
|
||||
var children = [],
|
||||
sorted = SortNodes(tree_data),
|
||||
j, all_hosts;
|
||||
|
||||
for (j = 0; j < sorted.length; j++) {
|
||||
children.push(sorted[j].id);
|
||||
}
|
||||
|
||||
all_hosts = {
|
||||
name: 'All Hosts',
|
||||
id: 1,
|
||||
group_id: null,
|
||||
parent: 0,
|
||||
description: '',
|
||||
show: true,
|
||||
ngicon: null,
|
||||
has_children: false,
|
||||
related: {},
|
||||
selected_class: '',
|
||||
show_failures: false,
|
||||
isDraggable: false,
|
||||
isDroppable: true,
|
||||
children: children
|
||||
};
|
||||
groups.push(all_hosts);
|
||||
}
|
||||
|
||||
function buildGroups(tree_data, parent, level) {
|
||||
var sorted = SortNodes(tree_data);
|
||||
for (var i=0; i < sorted.length; i++) {
|
||||
|
||||
var i, j, children, stat, hosts_status, group,
|
||||
sorted = SortNodes(tree_data);
|
||||
|
||||
for (i = 0; i < sorted.length; i++) {
|
||||
id++;
|
||||
|
||||
var stat = GetSyncStatusMsg({
|
||||
stat = GetSyncStatusMsg({
|
||||
status: sorted[i].summary_fields.inventory_source.status
|
||||
}); // from helpers/Groups.js
|
||||
|
||||
var hosts_status = GetHostsStatusMsg({
|
||||
}); // from helpers/Groups.js
|
||||
|
||||
hosts_status = GetHostsStatusMsg({
|
||||
active_failures: sorted[i].hosts_with_active_failures,
|
||||
total_hosts: sorted[i].total_hosts,
|
||||
inventory_id: inventory_id,
|
||||
inventory_id: inventory_id,
|
||||
group_id: sorted[i].id
|
||||
}); // from helpers/Groups.js
|
||||
|
||||
var children = [];
|
||||
for (var j=0; j < sorted[i].children.length; j++) {
|
||||
}); // from helpers/Groups.js
|
||||
|
||||
children = [];
|
||||
for (j = 0; j < sorted[i].children.length; j++) {
|
||||
children.push(sorted[i].children[j].id);
|
||||
}
|
||||
|
||||
var group = {
|
||||
}
|
||||
|
||||
group = {
|
||||
name: sorted[i].name,
|
||||
has_active_failures: sorted[i].has_active_failures,
|
||||
total_hosts: sorted[i].total_hosts,
|
||||
hosts_with_active_failures: sorted[i].hosts_with_active_failures,
|
||||
total_groups: sorted[i].total_groups,
|
||||
groups_with_active_failures: sorted[i].groups_with_active_failures,
|
||||
parent: parent,
|
||||
parent: parent,
|
||||
has_children: (sorted[i].children.length > 0) ? true : false,
|
||||
has_inventory_sources: sorted[i].has_inventory_sources,
|
||||
id: id,
|
||||
@ -97,25 +114,25 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
children: children,
|
||||
ngicon: (sorted[i].children.length > 0) ? 'fa fa-minus-square-o node-toggle' : 'fa fa-square-o node-no-toggle',
|
||||
ngclick: 'toggle(' + id + ')',
|
||||
related: {
|
||||
children: (sorted[i].children.length > 0) ? sorted[i].related.children : '',
|
||||
related: {
|
||||
children: (sorted[i].children.length > 0) ? sorted[i].related.children : '',
|
||||
inventory_source: sorted[i].related.inventory_source
|
||||
},
|
||||
},
|
||||
status: sorted[i].summary_fields.inventory_source.status,
|
||||
status_class: stat['class'],
|
||||
status_tooltip: stat['tooltip'],
|
||||
launch_tooltip: stat['launch_tip'],
|
||||
launch_class: stat['launch_class'],
|
||||
hosts_status_tip: hosts_status['tooltip'],
|
||||
show_failures: hosts_status['failures'],
|
||||
status_tooltip: stat.tooltip,
|
||||
launch_tooltip: stat.launch_tip,
|
||||
launch_class: stat.launch_class,
|
||||
hosts_status_tip: hosts_status.tooltip,
|
||||
show_failures: hosts_status.failures,
|
||||
hosts_status_class: hosts_status['class'],
|
||||
selected_class: '',
|
||||
show: true,
|
||||
isDraggable: true,
|
||||
isDraggable: true,
|
||||
isDroppable: true
|
||||
}
|
||||
};
|
||||
groups.push(group);
|
||||
if (new_group_id && group.group_id == new_group_id) {
|
||||
if (new_group_id && group.group_id === new_group_id) {
|
||||
// For new group
|
||||
scope.selected_tree_id = id;
|
||||
scope.selected_group_id = group.group_id;
|
||||
@ -130,62 +147,66 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
if (scope.buildAllGroupsRemove) {
|
||||
scope.buildAllGroupsRemove();
|
||||
}
|
||||
scope.buildAllGroupsRemove = scope.$on('buildAllGroups', function(e, inventory_name, inventory_tree) {
|
||||
scope.buildAllGroupsRemove = scope.$on('buildAllGroups', function (e, inventory_name, inventory_tree) {
|
||||
Rest.setUrl(inventory_tree);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
.success(function (data) {
|
||||
buildAllHosts(data);
|
||||
buildGroups(data, 0, 0);
|
||||
scope.autoShowGroupHelp = (data.length == 0) ? true : false;
|
||||
scope.autoShowGroupHelp = (data.length === 0) ? true : false;
|
||||
if (refresh) {
|
||||
scope.groups = groups;
|
||||
scope.$emit('GroupTreeRefreshed', inventory_name, groups, emit);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
scope.$emit('GroupTreeLoaded', inventory_name, groups, emit);
|
||||
}
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
})
|
||||
.error(function (data, status) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to get inventory tree for: ' + inventory_id + '. GET returned: ' + status });
|
||||
ProcessErrors(scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to get inventory tree for: ' + inventory_id + '. GET returned: ' + status
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function loadTreeData() {
|
||||
// Load the inventory root node
|
||||
Wait('start');
|
||||
Rest.setUrl (GetBasePath('inventory') + inventory_id + '/');
|
||||
Rest.setUrl(GetBasePath('inventory') + inventory_id + '/');
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
.success(function (data) {
|
||||
scope.$emit('buildAllGroups', data.name, data.related.tree, data.related.groups);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
})
|
||||
.error(function (data, status) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to get inventory: ' + inventory_id + '. GET returned: ' + status });
|
||||
ProcessErrors(scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to get inventory: ' + inventory_id + '. GET returned: ' + status
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadTreeData();
|
||||
}
|
||||
}])
|
||||
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
// Update a group with a set of properties
|
||||
.factory('UpdateGroup', ['ApplyEllipsis', 'GetSyncStatusMsg', 'Empty',
|
||||
function(ApplyEllipsis, GetSyncStatusMsg, Empty) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var group_id = params.group_id;
|
||||
var properties = params.properties; // object of key:value pairs to update
|
||||
var old_name, stat;
|
||||
for (var i=0; i < scope.groups.length; i++) {
|
||||
|
||||
// Update a group with a set of properties
|
||||
.factory('UpdateGroup', ['ApplyEllipsis', 'GetSyncStatusMsg', 'Empty',
|
||||
function (ApplyEllipsis, GetSyncStatusMsg, Empty) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
group_id = params.group_id,
|
||||
properties = params.properties,
|
||||
i, p, grp, old_name, stat;
|
||||
for (i = 0; i < scope.groups.length; i++) {
|
||||
if (scope.groups[i].group_id === group_id) {
|
||||
var grp = scope.groups[i];
|
||||
for (var p in properties) {
|
||||
grp = scope.groups[i];
|
||||
for (p in properties) {
|
||||
if (p === 'name') {
|
||||
old_name = scope.groups[i].name;
|
||||
}
|
||||
@ -195,13 +216,14 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
if (!Empty(properties[p]) && (scope.groups[i].status === 'none' || Empty(scope.groups[i].status))) {
|
||||
// We have a source but no status, seed the status with 'never' to enable sync button
|
||||
scope.groups[i].status = 'never updated';
|
||||
}
|
||||
else if (!properties[p]) {
|
||||
} else if (!properties[p]) {
|
||||
// User removed source
|
||||
scope.groups[i].status = 'none';
|
||||
}
|
||||
// Update date sync status links/icons
|
||||
stat = GetSyncStatusMsg({ status: scope.groups[i].status });
|
||||
stat = GetSyncStatusMsg({
|
||||
status: scope.groups[i].status
|
||||
});
|
||||
scope.groups[i].status_class = stat['class'];
|
||||
scope.groups[i].status_tooltip = stat.tooltip;
|
||||
scope.groups[i].launch_tooltip = stat.launch_tip;
|
||||
@ -211,7 +233,7 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
scope.groups[i][p] = properties[p];
|
||||
}
|
||||
}
|
||||
if (scope.groups[i].id == scope.selected_tree_id) {
|
||||
if (scope.groups[i].id === scope.selected_tree_id) {
|
||||
//Make sure potential group name change gets reflected throughout the page
|
||||
scope.selected_group_name = scope.groups[i].name;
|
||||
scope.search_place_holder = 'Search ' + scope.groups[i].name;
|
||||
@ -221,77 +243,76 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
|
||||
// Update any titles attributes created by ApplyEllipsis
|
||||
if (old_name) {
|
||||
setTimeout(function() {
|
||||
$('#groups_table .group-name a[title="' + old_name + '"]').attr('title',properties.name);
|
||||
setTimeout(function () {
|
||||
$('#groups_table .group-name a[title="' + old_name + '"]').attr('title', properties.name);
|
||||
ApplyEllipsis('#groups_table .group-name a');
|
||||
}, 2500);
|
||||
}, 2500);
|
||||
}
|
||||
|
||||
}
|
||||
}])
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
// Set node name and description after an update to Group properties.
|
||||
.factory('SetNodeName', [ function() {
|
||||
return function(params) {
|
||||
var scope = params.scope;
|
||||
var name = params.name;
|
||||
var descr = params.description;
|
||||
var group_id = (params.group_id !== undefined) ? params.group_id : null;
|
||||
var inventory_id = (params.inventory_id != undefined) ? params.inventory_id : null;
|
||||
// Set node name and description after an update to Group properties.
|
||||
.factory('SetNodeName', [
|
||||
function () {
|
||||
return function (params) {
|
||||
var name = params.name,
|
||||
descr = params.description,
|
||||
group_id = (params.group_id !== undefined) ? params.group_id : null,
|
||||
inventory_id = (params.inventory_id !== undefined) ? params.inventory_id : null;
|
||||
|
||||
if (group_id !== null) {
|
||||
$('#inventory-tree').find('li [data-group-id="' + group_id + '"]').each(function(idx) {
|
||||
$(this).attr('data-name',name);
|
||||
$(this).attr('data-description',descr);
|
||||
$(this).find('.activate').first().text(name);
|
||||
});
|
||||
$('#inventory-tree').find('li [data-group-id="' + group_id + '"]').each(function () {
|
||||
$(this).attr('data-name', name);
|
||||
$(this).attr('data-description', descr);
|
||||
$(this).find('.activate').first().text(name);
|
||||
});
|
||||
}
|
||||
|
||||
if (inventory_id !== null) {
|
||||
$('#inventory-root-node').attr('data-name', name).attr('data-description', descr).find('.activate').first().text(name);
|
||||
}
|
||||
}
|
||||
}])
|
||||
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
// Copy or Move a group on the tree after drag-n-drop
|
||||
.factory('CopyMoveGroup', ['$compile', 'Alert', 'ProcessErrors', 'Find', 'Wait', 'Rest', 'Empty', 'GetBasePath',
|
||||
function($compile, Alert, ProcessErrors, Find, Wait, Rest, Empty, GetBasePath) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var target = Find({ list: scope.groups, key: 'id', val: params.target_tree_id });
|
||||
var inbound = Find({ list: scope.groups, key: 'id', val: params.inbound_tree_id });
|
||||
|
||||
// Copy or Move a group on the tree after drag-n-drop
|
||||
.factory('CopyMoveGroup', ['$compile', 'Alert', 'ProcessErrors', 'Find', 'Wait', 'Rest', 'Empty', 'GetBasePath',
|
||||
function ($compile, Alert, ProcessErrors, Find, Wait, Rest, Empty, GetBasePath) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
target = Find({ list: scope.groups, key: 'id', val: params.target_tree_id }),
|
||||
inbound = Find({ list: scope.groups, key: 'id', val: params.inbound_tree_id }),
|
||||
e, html = '';
|
||||
|
||||
// Build the html for our prompt dialog
|
||||
var html = '';
|
||||
html += "<div id=\"copy-prompt-modal\" class=\"modal fade\">\n";
|
||||
html += "<div class=\"modal-dialog\">\n";
|
||||
html += "<div class=\"modal-content\">\n";
|
||||
html += "<div class=\"modal-header\">\n";
|
||||
html += "<button type=\"button\" class=\"close\" data-target=\"#copy-prompt-modal\" " +
|
||||
html += "<button type=\"button\" class=\"close\" data-target=\"#copy-prompt-modal\" " +
|
||||
"data-dismiss=\"modal\" aria-hidden=\"true\">×</button>\n";
|
||||
|
||||
if (target.id == 1 || inbound.parent == 0) {
|
||||
// We're moving the group to the top level, or we're moving a top level group down
|
||||
html += "<h3>Move Group</h3>\n";
|
||||
}
|
||||
else {
|
||||
html += "<h3>Copy or Move?</h3>\n";
|
||||
|
||||
if (target.id === 1 || inbound.parent === 0) {
|
||||
// We're moving the group to the top level, or we're moving a top level group down
|
||||
html += "<h3>Move Group</h3>\n";
|
||||
} else {
|
||||
html += "<h3>Copy or Move?</h3>\n";
|
||||
}
|
||||
|
||||
html += "</div>\n";
|
||||
html += "<div class=\"modal-body\">\n";
|
||||
|
||||
if (target.id == 1) {
|
||||
|
||||
if (target.id === 1) {
|
||||
html += "<p>Are you sure you want to move group " + inbound.name + " to the top level?</p>";
|
||||
}
|
||||
else if (inbound.parent == 0) {
|
||||
} else if (inbound.parent === 0) {
|
||||
html += "<p>Are you sure you want to move group " + inbound.name + " from the top level and make it a child of " +
|
||||
target.name + "?</p>";
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
html += "<div class=\"text-center\">\n";
|
||||
html += "<p>Would you like to copy or move group <em>" + inbound.name + "</em> to group <em>" + target.name + "</em>?</p>\n";
|
||||
html += "<div style=\"margin-top: 30px;\">\n";
|
||||
@ -300,12 +321,12 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
}
|
||||
|
||||
|
||||
html += "</div>\n";
|
||||
html += "<div class=\"modal-footer\">\n";
|
||||
html += "<a href=\"#\" data-target=\"#prompt-modal\" data-dismiss=\"modal\" class=\"btn btn-default\">Cancel</a>\n";
|
||||
|
||||
if (target.id == 1 || inbound.parent == 0) {
|
||||
if (target.id === 1 || inbound.parent === 0) {
|
||||
// We're moving the group to the top level, or we're moving a top level group down
|
||||
html += "<a href=\"\" data-target=\"#prompt-modal\" ng-click=\"moveGroup()\" class=\"btn btn-primary\">Yes</a>\n";
|
||||
}
|
||||
@ -314,134 +335,135 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
html += "</div><!-- modal-content -->\n";
|
||||
html += "</div><!-- modal-dialog -->\n";
|
||||
html += "</div><!-- modal -->\n";
|
||||
|
||||
|
||||
// Inject our custom dialog
|
||||
var e = angular.element(document.getElementById('inventory-modal-container'));
|
||||
e= angular.element(document.getElementById('inventory-modal-container'));
|
||||
e.empty().append(html);
|
||||
$compile(e)(scope);
|
||||
|
||||
|
||||
// Display it
|
||||
$('#copy-prompt-modal').modal({
|
||||
backdrop: 'static',
|
||||
keyboard: true,
|
||||
show: true
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Respond to move
|
||||
scope.moveGroup = function() {
|
||||
|
||||
scope.moveGroup = function () {
|
||||
var url, group, parent;
|
||||
$('#copy-prompt-modal').modal('hide');
|
||||
Wait('start');
|
||||
|
||||
|
||||
// disassociate the group from the original parent
|
||||
if (scope.removeGroupRemove) {
|
||||
scope.removeGroupRemove();
|
||||
scope.removeGroupRemove();
|
||||
}
|
||||
scope.removeGroupRemove = scope.$on('removeGroup', function() {
|
||||
scope.removeGroupRemove = scope.$on('removeGroup', function () {
|
||||
if (inbound.parent > 0) {
|
||||
// Only remove a group from a parent when the parent is a group and not the inventory root
|
||||
var parent = Find({ list: scope.groups, key: 'id', val: inbound.parent })
|
||||
var url = GetBasePath('base') + 'groups/' + parent.group_id + '/children/';
|
||||
parent = Find({ list: scope.groups, key: 'id', val: inbound.parent });
|
||||
url = GetBasePath('base') + 'groups/' + parent.group_id + '/children/';
|
||||
Rest.setUrl(url);
|
||||
Rest.post({ id: inbound.group_id, disassociate: 1 })
|
||||
.success( function(data, status, headers, config) {
|
||||
.success(function () {
|
||||
//Triggers refresh of group list in inventory controller
|
||||
scope.$emit('GroupDeleteCompleted');
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
scope.$emit('GroupDeleteCompleted');
|
||||
})
|
||||
.error(function (data, status) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to remove ' + inbound.name +
|
||||
' from ' + parent.name + '. POST returned status: ' + status });
|
||||
ProcessErrors(scope, data, status, null, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to remove ' + inbound.name +
|
||||
' from ' + parent.name + '. POST returned status: ' + status
|
||||
});
|
||||
}
|
||||
else {
|
||||
});
|
||||
} else {
|
||||
//Triggers refresh of group list in inventory controller
|
||||
scope.$emit('GroupDeleteCompleted');
|
||||
scope.$emit('GroupDeleteCompleted');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// add the new group to the target parent
|
||||
var url = (!Empty(target.group_id)) ?
|
||||
GetBasePath('base') + 'groups/' + target.group_id + '/children/' :
|
||||
GetBasePath('inventory') + scope.inventory_id + '/groups/';
|
||||
var group = {
|
||||
url = (!Empty(target.group_id)) ?
|
||||
GetBasePath('base') + 'groups/' + target.group_id + '/children/' :
|
||||
GetBasePath('inventory') + scope.inventory_id + '/groups/';
|
||||
group = {
|
||||
id: inbound.group_id,
|
||||
name: inbound.name,
|
||||
description: inbound.description,
|
||||
inventory: scope.inventory_id
|
||||
}
|
||||
};
|
||||
Rest.setUrl(url);
|
||||
Rest.post(group)
|
||||
.success( function(data, status, headers, config) {
|
||||
.success(function () {
|
||||
scope.$emit('removeGroup');
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
})
|
||||
.error(function (data, status) {
|
||||
var target_name = (Empty(target.group_id)) ? 'inventory' : target.name;
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to add ' + node.attr('name') + ' to ' +
|
||||
target_name + '. POST returned status: ' + status });
|
||||
});
|
||||
}
|
||||
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to add ' + inbound.name + ' to ' + target_name + '. POST returned status: ' + status });
|
||||
});
|
||||
};
|
||||
|
||||
scope.copyGroup = function() {
|
||||
|
||||
scope.copyGroup = function () {
|
||||
$('#copy-prompt-modal').modal('hide');
|
||||
Wait('start');
|
||||
// add the new group to the target parent
|
||||
var url = (!Empty(target.group_id)) ?
|
||||
GetBasePath('base') + 'groups/' + target.group_id + '/children/' :
|
||||
GetBasePath('inventory') + scope.inventory_id + '/groups/';
|
||||
var group = {
|
||||
id: inbound.group_id,
|
||||
name: inbound.name,
|
||||
description: inbound.description,
|
||||
inventory: scope.inventory_id
|
||||
}
|
||||
var url = (!Empty(target.group_id)) ?
|
||||
GetBasePath('base') + 'groups/' + target.group_id + '/children/' :
|
||||
GetBasePath('inventory') + scope.inventory_id + '/groups/',
|
||||
group = {
|
||||
id: inbound.group_id,
|
||||
name: inbound.name,
|
||||
description: inbound.description,
|
||||
inventory: scope.inventory_id
|
||||
};
|
||||
|
||||
Rest.setUrl(url);
|
||||
Rest.post(group)
|
||||
.success( function(data, status, headers, config) {
|
||||
//Triggers refresh of group list in inventory controller
|
||||
scope.$emit('GroupDeleteCompleted');
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
var target_name = (Empty(target.group_id)) ? 'inventory' : target.name;
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to add ' + inbound.name + ' to ' +
|
||||
target_name + '. POST returned status: ' + status });
|
||||
});
|
||||
}
|
||||
.success(function () {
|
||||
//Triggers refresh of group list in inventory controller
|
||||
scope.$emit('GroupDeleteCompleted');
|
||||
})
|
||||
.error(function (data, status) {
|
||||
var target_name = (Empty(target.group_id)) ? 'inventory' : target.name;
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to add ' + inbound.name + ' to ' + target_name + '. POST returned status: ' + status
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
}
|
||||
}])
|
||||
|
||||
// Copy a host after drag-n-drop
|
||||
.factory('CopyMoveHost', ['$compile', 'Alert', 'ProcessErrors', 'Find', 'Wait', 'Rest', 'Empty', 'GetBasePath',
|
||||
function($compile, Alert, ProcessErrors, Find, Wait, Rest, Empty, GetBasePath) {
|
||||
return function(params) {
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
// Copy a host after drag-n-drop
|
||||
.factory('CopyMoveHost', ['$compile', 'Alert', 'ProcessErrors', 'Find', 'Wait', 'Rest', 'Empty', 'GetBasePath',
|
||||
function ($compile, Alert, ProcessErrors, Find, Wait, Rest, Empty, GetBasePath) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
target = Find({ list: scope.groups, key: 'id', val: params.target_tree_id }),
|
||||
host = Find({ list: scope.hosts, key: 'id', val: params.host_id }),
|
||||
found = false, i;
|
||||
|
||||
found = false, e, i, html = '';
|
||||
|
||||
if (host.summary_fields.all_groups) {
|
||||
for (i=0; i< host.summary_fields.all_groups.length; i++) {
|
||||
if (host.summary_fields.all_groups[i].id == target.group_id) {
|
||||
found = true;
|
||||
break;
|
||||
for (i = 0; i < host.summary_fields.all_groups.length; i++) {
|
||||
if (host.summary_fields.all_groups[i].id === target.group_id) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
var html = '';
|
||||
html += "<div id=\"copy-alert-modal\" class=\"modal fade\">\n";
|
||||
html += "<div class=\"modal-dialog\">\n";
|
||||
html += "<div class=\"modal-content\">\n";
|
||||
html += "<div class=\"modal-header\">\n";
|
||||
html += "<button type=\"button\" class=\"close\" ng-hide=\"disableButtons\" data-target=\"#copy-alert-modal\"\n";
|
||||
html += "<button type=\"button\" class=\"close\" ng-hide=\"disableButtons\" data-target=\"#copy-alert-modal\"\n";
|
||||
html += "data-dismiss=\"modal\" class=\"modal\" aria-hidden=\"true\">×</button>\n";
|
||||
html += "<h3>Already in Group</h3>\n";
|
||||
html += "</div>\n";
|
||||
@ -456,31 +478,30 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
html += "</div>\n";
|
||||
|
||||
// Inject our custom dialog
|
||||
var e = angular.element(document.getElementById('inventory-modal-container'));
|
||||
e = angular.element(document.getElementById('inventory-modal-container'));
|
||||
e.empty().append(html);
|
||||
$compile(e)(scope);
|
||||
|
||||
|
||||
// Display it
|
||||
$('#copy-alert-modal').modal({
|
||||
backdrop: 'static',
|
||||
keyboard: true,
|
||||
show: true
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
});
|
||||
|
||||
} else {
|
||||
// Build the html for our prompt dialog
|
||||
var html = '';
|
||||
html = '';
|
||||
html += "<div id=\"copy-prompt-modal\" class=\"modal fade\">\n";
|
||||
html += "<div class=\"modal-dialog\">\n";
|
||||
html += "<div class=\"modal-content\">\n";
|
||||
html += "<div class=\"modal-header\">\n";
|
||||
html += "<button type=\"button\" class=\"close\" data-target=\"#copy-prompt-modal\" " +
|
||||
html += "<button type=\"button\" class=\"close\" data-target=\"#copy-prompt-modal\" " +
|
||||
"data-dismiss=\"modal\" aria-hidden=\"true\">×</button>\n";
|
||||
html += "<h3>Copy Host</h3>\n";
|
||||
html += "</div>\n";
|
||||
html += "<div class=\"modal-body\">\n";
|
||||
html += "<p>Are you sure you want to copy host " + host.name + ' to group ' + target.name + '?</p>';
|
||||
html += "<p>Are you sure you want to copy host " + host.name + ' to group ' + target.name + '?</p>';
|
||||
html += "</div>\n";
|
||||
html += "<div class=\"modal-footer\">\n";
|
||||
html += "<a href=\"#\" data-target=\"#prompt-modal\" data-dismiss=\"modal\" class=\"btn btn-default\">No</a>\n";
|
||||
@ -489,35 +510,35 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
html += "</div><!-- modal-content -->\n";
|
||||
html += "</div><!-- modal-dialog -->\n";
|
||||
html += "</div><!-- modal -->\n";
|
||||
|
||||
|
||||
// Inject our custom dialog
|
||||
var e = angular.element(document.getElementById('inventory-modal-container'));
|
||||
e = angular.element(document.getElementById('inventory-modal-container'));
|
||||
e.empty().append(html);
|
||||
$compile(e)(scope);
|
||||
|
||||
|
||||
// Display it
|
||||
$('#copy-prompt-modal').modal({
|
||||
backdrop: 'static',
|
||||
keyboard: true,
|
||||
show: true
|
||||
});
|
||||
});
|
||||
|
||||
scope.copyHost = function() {
|
||||
scope.copyHost = function () {
|
||||
$('#copy-prompt-modal').modal('hide');
|
||||
Wait('start');
|
||||
Rest.setUrl(GetBasePath('groups') + target.group_id + '/hosts/');
|
||||
Rest.post(host)
|
||||
.success(function(data, status, headers, config) {
|
||||
.success(function () {
|
||||
// Signal the controller to refresh the hosts view
|
||||
scope.$emit('GroupTreeRefreshed');
|
||||
})
|
||||
.error(function(data, status, headers, config) {
|
||||
})
|
||||
.error(function (data, status) {
|
||||
Wait('stop');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to add ' + host.name + ' to ' +
|
||||
target.name + '. POST returned status: ' + status });
|
||||
});
|
||||
}
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!', msg: 'Failed to add ' + host.name + ' to ' +
|
||||
target.name + '. POST returned status: ' + status });
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
}]);
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -4,154 +4,194 @@
|
||||
* Generic accessor for Ansible Commander services
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
angular.module('RestServices',['ngCookies','AuthService'])
|
||||
.factory('Rest', ['$http','$rootScope','$cookieStore', '$q', 'Authorization',
|
||||
function($http, $rootScope, $cookieStore, $q, Authorization) {
|
||||
return {
|
||||
|
||||
headers: {},
|
||||
angular.module('RestServices', ['ngCookies', 'AuthService'])
|
||||
.factory('Rest', ['$http', '$rootScope', '$cookieStore', '$q', 'Authorization',
|
||||
function ($http, $rootScope, $cookieStore, $q, Authorization) {
|
||||
return {
|
||||
|
||||
setUrl: function (url) {
|
||||
this.url = url;
|
||||
},
|
||||
checkExpired: function() {
|
||||
return $rootScope.sessionTimer.isExpired();
|
||||
},
|
||||
pReplace: function() {
|
||||
//in our url, replace :xx params with a value, assuming
|
||||
//we can find it in user supplied params.
|
||||
var key,rgx;
|
||||
for (key in this.params) {
|
||||
rgx = new RegExp("\\:" + key,'gm');
|
||||
if (rgx.test(this.url)) {
|
||||
this.url = this.url.replace(rgx,this.params[key]);
|
||||
delete this.params[key];
|
||||
}
|
||||
}
|
||||
},
|
||||
createResponse: function(data, status) {
|
||||
// Simulate an http response when a token error occurs
|
||||
// http://stackoverflow.com/questions/18243286/angularjs-promises-simulate-http-promises
|
||||
|
||||
var promise = $q.reject({ data: data, status: status });
|
||||
promise.success = function(fn){
|
||||
promise.then(function(response){ fn(response.data, response.status) }, null);
|
||||
return promise
|
||||
headers: {},
|
||||
|
||||
setUrl: function (url) {
|
||||
this.url = url;
|
||||
},
|
||||
checkExpired: function () {
|
||||
return $rootScope.sessionTimer.isExpired();
|
||||
},
|
||||
pReplace: function () {
|
||||
//in our url, replace :xx params with a value, assuming
|
||||
//we can find it in user supplied params.
|
||||
var key, rgx;
|
||||
for (key in this.params) {
|
||||
rgx = new RegExp("\\:" + key, 'gm');
|
||||
if (rgx.test(this.url)) {
|
||||
this.url = this.url.replace(rgx, this.params[key]);
|
||||
delete this.params[key];
|
||||
}
|
||||
}
|
||||
},
|
||||
createResponse: function (data, status) {
|
||||
// Simulate an http response when a token error occurs
|
||||
// http://stackoverflow.com/questions/18243286/angularjs-promises-simulate-http-promises
|
||||
|
||||
var promise = $q.reject({
|
||||
data: data,
|
||||
status: status
|
||||
});
|
||||
promise.success = function (fn) {
|
||||
promise.then(function (response) {
|
||||
fn(response.data, response.status);
|
||||
}, null);
|
||||
return promise;
|
||||
};
|
||||
promise.error = function (fn) {
|
||||
promise.then(null, function (response) {
|
||||
fn(response.data, response.status);
|
||||
});
|
||||
return promise;
|
||||
};
|
||||
return promise;
|
||||
},
|
||||
|
||||
setHeader: function (hdr) {
|
||||
// Pass in { key: value } pairs to be added to the header
|
||||
for (var h in hdr) {
|
||||
this.headers[h] = hdr[h];
|
||||
}
|
||||
},
|
||||
get: function (args) {
|
||||
args = (args) ? args : {};
|
||||
this.params = (args.params) ? args.params : null;
|
||||
this.pReplace();
|
||||
var expired = this.checkExpired(),
|
||||
token = Authorization.getToken();
|
||||
if (expired) {
|
||||
return this.createResponse({
|
||||
detail: 'Token is expired'
|
||||
}, 401);
|
||||
} else if (token) {
|
||||
this.setHeader({
|
||||
Authorization: 'Token ' + token
|
||||
});
|
||||
this.setHeader({
|
||||
"X-Auth-Token": 'Token ' + token
|
||||
});
|
||||
return $http({
|
||||
method: 'GET',
|
||||
url: this.url,
|
||||
headers: this.headers,
|
||||
params: this.params
|
||||
});
|
||||
} else {
|
||||
return this.createResponse({
|
||||
detail: 'Invalid token'
|
||||
}, 401);
|
||||
}
|
||||
},
|
||||
post: function (data) {
|
||||
var token = Authorization.getToken(),
|
||||
expired = this.checkExpired();
|
||||
if (expired) {
|
||||
return this.createResponse({
|
||||
detail: 'Token is expired'
|
||||
}, 401);
|
||||
} else if (token) {
|
||||
this.setHeader({
|
||||
Authorization: 'Token ' + token
|
||||
});
|
||||
this.setHeader({
|
||||
"X-Auth-Token": 'Token ' + token
|
||||
});
|
||||
return $http({
|
||||
method: 'POST',
|
||||
url: this.url,
|
||||
headers: this.headers,
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
return this.createResponse({
|
||||
detail: 'Invalid token'
|
||||
}, 401);
|
||||
}
|
||||
},
|
||||
put: function (data) {
|
||||
var token = Authorization.getToken(),
|
||||
expired = this.checkExpired();
|
||||
if (expired) {
|
||||
return this.createResponse({
|
||||
detail: 'Token is expired'
|
||||
}, 401);
|
||||
} else if (token) {
|
||||
this.setHeader({
|
||||
Authorization: 'Token ' + token
|
||||
});
|
||||
this.setHeader({
|
||||
"X-Auth-Token": 'Token ' + token
|
||||
});
|
||||
return $http({
|
||||
method: 'PUT',
|
||||
url: this.url,
|
||||
headers: this.headers,
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
return this.createResponse({
|
||||
detail: 'Invalid token'
|
||||
}, 401);
|
||||
}
|
||||
},
|
||||
destroy: function (data) {
|
||||
var token = Authorization.getToken(),
|
||||
expired = this.checkExpired();
|
||||
if (expired) {
|
||||
return this.createResponse({
|
||||
detail: 'Token is expired'
|
||||
}, 401);
|
||||
} else if (token) {
|
||||
this.setHeader({
|
||||
Authorization: 'Token ' + token
|
||||
});
|
||||
this.setHeader({
|
||||
"X-Auth-Token": 'Token ' + token
|
||||
});
|
||||
return $http({
|
||||
method: 'DELETE',
|
||||
url: this.url,
|
||||
headers: this.headers,
|
||||
data: data
|
||||
});
|
||||
} else {
|
||||
return this.createResponse({
|
||||
detail: 'Invalid token'
|
||||
}, 401);
|
||||
}
|
||||
},
|
||||
options: function () {
|
||||
var token = Authorization.getToken(),
|
||||
expired = this.checkExpired();
|
||||
if (expired) {
|
||||
return this.createResponse({
|
||||
detail: 'Token is expired'
|
||||
}, 401);
|
||||
} else if (token) {
|
||||
this.setHeader({
|
||||
Authorization: 'Token ' + token
|
||||
});
|
||||
this.setHeader({
|
||||
"X-Auth-Token": 'Token ' + token
|
||||
});
|
||||
return $http({
|
||||
method: 'OPTIONS',
|
||||
url: this.url,
|
||||
headers: this.headers
|
||||
});
|
||||
} else {
|
||||
return this.createResponse({
|
||||
detail: 'Invalid token'
|
||||
}, 401);
|
||||
}
|
||||
}
|
||||
};
|
||||
promise.error = function(fn){
|
||||
promise.then(null, function(response){ fn(response.data, response.status) });
|
||||
return promise;
|
||||
};
|
||||
return promise;
|
||||
},
|
||||
|
||||
setHeader: function(hdr) {
|
||||
// Pass in { key: value } pairs to be added to the header
|
||||
for (var h in hdr) {
|
||||
this.headers[h] = hdr[h];
|
||||
}
|
||||
},
|
||||
get: function(args) {
|
||||
args = (args) ? args : {};
|
||||
this.params = (args.params) ? args.params : null;
|
||||
this.pReplace();
|
||||
var expired = this.checkExpired();
|
||||
var token = Authorization.getToken();
|
||||
if (expired) {
|
||||
return this.createResponse({ detail: 'Token is expired' }, 401);
|
||||
}
|
||||
else if (token) {
|
||||
this.setHeader({ Authorization: 'Token ' + token });
|
||||
this.setHeader({ "X-Auth-Token": 'Token ' + token });
|
||||
return $http({method: 'GET',
|
||||
url: this.url,
|
||||
headers: this.headers,
|
||||
params: this.params
|
||||
});
|
||||
}
|
||||
else {
|
||||
return this.createResponse({ detail: 'Invalid token' }, 401);
|
||||
}
|
||||
},
|
||||
post: function(data) {
|
||||
var token = Authorization.getToken();
|
||||
var expired = this.checkExpired();
|
||||
if (expired) {
|
||||
return this.createResponse({ detail: 'Token is expired' }, 401);
|
||||
}
|
||||
else if (token) {
|
||||
this.setHeader({ Authorization: 'Token ' + token });
|
||||
this.setHeader({ "X-Auth-Token": 'Token ' + token });
|
||||
return $http({
|
||||
method: 'POST',
|
||||
url: this.url,
|
||||
headers: this.headers,
|
||||
data: data });
|
||||
}
|
||||
else {
|
||||
return this.createResponse({ detail: 'Invalid token' }, 401);
|
||||
}
|
||||
},
|
||||
put: function(data) {
|
||||
var token = Authorization.getToken();
|
||||
var expired = this.checkExpired();
|
||||
if (expired) {
|
||||
return this.createResponse({ detail: 'Token is expired' }, 401);
|
||||
}
|
||||
else if (token) {
|
||||
this.setHeader({ Authorization: 'Token ' + token });
|
||||
this.setHeader({ "X-Auth-Token": 'Token ' + token });
|
||||
return $http({
|
||||
method: 'PUT',
|
||||
url: this.url,
|
||||
headers: this.headers,
|
||||
data: data });
|
||||
}
|
||||
else {
|
||||
return this.createResponse({ detail: 'Invalid token' }, 401);
|
||||
}
|
||||
},
|
||||
destroy: function(data) {
|
||||
var token = Authorization.getToken();
|
||||
var expired = this.checkExpired();
|
||||
if (expired) {
|
||||
return this.createResponse({ detail: 'Token is expired' }, 401);
|
||||
}
|
||||
else if (token) {
|
||||
this.setHeader({ Authorization: 'Token ' + token });
|
||||
this.setHeader({ "X-Auth-Token": 'Token ' + token });
|
||||
return $http({
|
||||
method: 'DELETE',
|
||||
url: this.url,
|
||||
headers: this.headers,
|
||||
data: data });
|
||||
}
|
||||
else {
|
||||
return this.createResponse({ detail: 'Invalid token' }, 401);
|
||||
}
|
||||
},
|
||||
options: function() {
|
||||
var token = Authorization.getToken();
|
||||
var expired = this.checkExpired();
|
||||
if (expired) {
|
||||
return this.createResponse({ detail: 'Token is expired' }, 401);
|
||||
}
|
||||
else if (token) {
|
||||
this.setHeader({ Authorization: 'Token ' + token });
|
||||
this.setHeader({ "X-Auth-Token": 'Token ' + token });
|
||||
return $http({
|
||||
method: 'OPTIONS',
|
||||
url: this.url,
|
||||
headers: this.headers
|
||||
});
|
||||
}
|
||||
else {
|
||||
return this.createResponse({ detail: 'Invalid token' }, 401);
|
||||
}
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
]);
|
||||
@ -7,52 +7,51 @@
|
||||
* duration set in config.js
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('TimerService', ['ngCookies', 'Utilities'])
|
||||
.factory('Timer', ['$rootScope', '$cookieStore', '$location', 'GetBasePath', 'Empty',
|
||||
function($rootScope, $cookieStore, $location, GetBasePath, Empty) {
|
||||
return {
|
||||
.factory('Timer', ['$rootScope', '$cookieStore', '$location', 'GetBasePath', 'Empty',
|
||||
function ($rootScope, $cookieStore) {
|
||||
return {
|
||||
|
||||
sessionTime: null,
|
||||
timeout: null,
|
||||
|
||||
getSessionTime: function() {
|
||||
return (this.sessionTime) ? this.sessionTime : $cookieStore.get('sessionTime');
|
||||
},
|
||||
sessionTime: null,
|
||||
timeout: null,
|
||||
|
||||
isExpired: function() {
|
||||
var stime = this.getSessionTime();
|
||||
var now = new Date().getTime();
|
||||
if ((stime - now) <= 0) {
|
||||
//expired
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// not expired. move timer forward.
|
||||
this.moveForward();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
expireSession: function() {
|
||||
this.sessionTime = 0;
|
||||
$rootScope.sessionExpired = true;
|
||||
$cookieStore.put('sessionExpired', true);
|
||||
},
|
||||
getSessionTime: function () {
|
||||
return (this.sessionTime) ? this.sessionTime : $cookieStore.get('sessionTime');
|
||||
},
|
||||
|
||||
moveForward: function() {
|
||||
var t = new Date().getTime() + ($AnsibleConfig.session_timeout * 1000);
|
||||
this.sessionTime = t;
|
||||
$cookieStore.put('sessionTime', t);
|
||||
$rootScope.sessionExpired = false;
|
||||
$cookieStore.put('sessionExpired', false);
|
||||
},
|
||||
isExpired: function () {
|
||||
var stime = this.getSessionTime(),
|
||||
now = new Date().getTime();
|
||||
if ((stime - now) <= 0) {
|
||||
//expired
|
||||
return true;
|
||||
} else {
|
||||
// not expired. move timer forward.
|
||||
this.moveForward();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
init: function() {
|
||||
this.moveForward();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}]);
|
||||
expireSession: function () {
|
||||
this.sessionTime = 0;
|
||||
$rootScope.sessionExpired = true;
|
||||
$cookieStore.put('sessionExpired', true);
|
||||
},
|
||||
|
||||
moveForward: function () {
|
||||
var t = new Date().getTime() + ($AnsibleConfig.session_timeout * 1000);
|
||||
this.sessionTime = t;
|
||||
$cookieStore.put('sessionTime', t);
|
||||
$rootScope.sessionExpired = false;
|
||||
$cookieStore.put('sessionExpired', false);
|
||||
},
|
||||
|
||||
init: function () {
|
||||
this.moveForward();
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -1,693 +0,0 @@
|
||||
|
||||
/************************************
|
||||
*
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* TreeSelector.js
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('TreeSelector', ['Utilities', 'RestServices', 'TreeSelector', 'GroupsHelper'])
|
||||
|
||||
.factory('SortNodes', [ function() {
|
||||
return function(data) {
|
||||
//Sort nodes by name
|
||||
var names = [];
|
||||
var newData = [];
|
||||
for (var i=0; i < data.length; i++) {
|
||||
names.push(data[i].name);
|
||||
}
|
||||
names.sort();
|
||||
for (var j=0; j < names.length; j++) {
|
||||
for (i=0; i < data.length; i++) {
|
||||
if (data[i].name == names[j]) {
|
||||
newData.push(data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newData;
|
||||
}
|
||||
}])
|
||||
|
||||
// Figure out the group level tool tip
|
||||
.factory('GetToolTip', [ 'FormatDate', function(FormatDate) {
|
||||
return function(params) {
|
||||
|
||||
var node = params.node;
|
||||
|
||||
var tip = '';
|
||||
var link = '';
|
||||
var html_class = '';
|
||||
var active_failures = node.hosts_with_active_failures;
|
||||
var total_hosts = node.total_hosts;
|
||||
var source = node.summary_fields.inventory_source.source;
|
||||
var status = node.summary_fields.inventory_source.status;
|
||||
|
||||
// Return values for the status indicator
|
||||
var status_date = node.summary_fields.inventory_source.last_updated
|
||||
var last_update = ( status_date == "" || status_date == null ) ? null : FormatDate(new Date(status_date));
|
||||
|
||||
switch (status) {
|
||||
case 'never updated':
|
||||
html_class = 'na';
|
||||
tip = '<p>Inventory update has not been performed.</p>';
|
||||
link = '';
|
||||
break;
|
||||
case 'failed':
|
||||
tip = '<p>Inventory update failed! Click to view process output.</p>';
|
||||
link = '/#/inventories/' + node.inventory + '/groups?name=' + node.name;
|
||||
html_class = true;
|
||||
break;
|
||||
case 'successful':
|
||||
tip = '<p>Inventory update completed on ' + last_update + '.</p>';
|
||||
html_class = false;
|
||||
link = '';
|
||||
break;
|
||||
case 'updating':
|
||||
tip = '<p>Inventory update process running now. Click to view status.</p>';
|
||||
link = '/#/inventories/' + node.inventory + '/groups?name=' + node.name;
|
||||
html_class = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status !== 'failed' && status !== 'updating') {
|
||||
// update status will not override job status
|
||||
if (active_failures > 0) {
|
||||
tip += "<p>Contains " + active_failures +
|
||||
[ (active_failures == 1) ? ' host' : ' hosts' ] + ' with failed jobs. Click to view the offending ' +
|
||||
[ (active_failures == 1) ? ' host' : ' hosts' ] + '.</p>';
|
||||
link = '/#/inventories/' + node.inventory + '/hosts?has_active_failures=true';
|
||||
html_class = 'true';
|
||||
}
|
||||
else {
|
||||
if (total_hosts == 0) {
|
||||
// no hosts
|
||||
tip += "<p>There are no hosts in this group. It's a sad empty shell.</p>";
|
||||
html_class = (html_class == '') ? 'na' : html_class;
|
||||
}
|
||||
else if (total_hosts == 1) {
|
||||
// on host with 0 failures
|
||||
tip += "<p>The 1 host in this group is happy! It does not have a job failure.</p>";
|
||||
html_class = 'false';
|
||||
}
|
||||
else {
|
||||
// many hosts with 0 failures
|
||||
tip += "<p>All " + total_hosts + " hosts in this group are happy! None of them have " +
|
||||
" job failures.</p>";
|
||||
html_class = 'false';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { tooltip: tip, url: link, 'class': html_class };
|
||||
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('GetInventoryToolTip', [ 'FormatDate', function(FormatDate) {
|
||||
return function(params) {
|
||||
|
||||
var node = params.node;
|
||||
|
||||
var tip = '';
|
||||
var link = '';
|
||||
var html_class = '';
|
||||
var active_failures = node.hosts_with_active_failures;
|
||||
var total_hosts = node.total_hosts;
|
||||
var group_failures = node.groups_with_active_failures;
|
||||
var total_groups = node.total_groups;
|
||||
var inventory_sources = node.total_inventory_sources;
|
||||
|
||||
if (group_failures > 0) {
|
||||
tip += "Has " + group_failures +
|
||||
[ (group_failures == 1) ? ' group' : ' groups' ] + ' with failed inventory updates. ' +
|
||||
'Click to view the offending ' +
|
||||
[ (group_failures == 1) ? ' group.' : ' groups.' ];
|
||||
link = '/#/inventories/' + node.id + '/groups?status=failed';
|
||||
html_class = 'true';
|
||||
}
|
||||
else if (inventory_sources == 1) {
|
||||
// on host with 0 failures
|
||||
tip += "<p>1 group with an inventory source is happy! No updates have failed.</p>";
|
||||
link = '';
|
||||
html_class = 'false';
|
||||
}
|
||||
else if (inventory_sources > 0) {
|
||||
tip += "<p>" + inventory_sources + " groups with an inventory source are happy! No updates have failed.</p>";
|
||||
link = 0;
|
||||
html_class = 'false';
|
||||
}
|
||||
|
||||
if (html_class !== 'true') {
|
||||
// Add job status
|
||||
if (active_failures > 0) {
|
||||
tip += "<p>Contains " + scope.inventories[i].hosts_with_active_failures +
|
||||
[ (active_failures == 1) ? ' host' : ' hosts' ] + ' with job failures. Click to view the offending ' +
|
||||
[ (active_failures == 1) ? ' host' : ' hosts' ] + '.</p>';
|
||||
link = '/#/inventories/' + node.id + '/hosts?has_active_failures=true';
|
||||
html_class = 'true';
|
||||
}
|
||||
else if (total_hosts == 0) {
|
||||
tip += "<p>There are no hosts in this inventory. It's a sad empty shell.</p>";
|
||||
link = "";
|
||||
html_class = (html_class == '') ? 'na' : html_class;
|
||||
}
|
||||
else if (total_hosts == 1) {
|
||||
tip += "<p>The 1 host found in this inventory is happy! There are no job failures.</p>";
|
||||
link = "";
|
||||
html_class = "false";
|
||||
}
|
||||
else if (total_hosts > 0) {
|
||||
tip += "<p>All " + total_hosts + " hosts are happy! There are no job failures.";
|
||||
link = "";
|
||||
html_class = "false";
|
||||
}
|
||||
}
|
||||
|
||||
return { tooltip: tip, url: link, 'class': html_class };
|
||||
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('BuildTree', ['Rest', 'GetBasePath', 'ProcessErrors', '$compile', '$rootScope', 'Wait', 'SortNodes', 'GetToolTip',
|
||||
'GetInventoryToolTip',
|
||||
function(Rest, GetBasePath, ProcessErrors, $compile, $rootScope, Wait, SortNodes, GetToolTip, GetInventoryToolTip) {
|
||||
return function(params) {
|
||||
var scope = params.scope;
|
||||
var inventory_id = params.inventory_id;
|
||||
var emit_on_select = params.emit_on_select;
|
||||
var target_id = params.target_id;
|
||||
var refresh_tree = (params.refresh == undefined || params.refresh == false) ? false : true;
|
||||
var moveable = (params.moveable == undefined || params.moveable == false) ? false : true;
|
||||
var group_id = params.group_id;
|
||||
var id = params.id;
|
||||
|
||||
var html = '';
|
||||
var toolTip = 'Hosts have failed jobs?';
|
||||
var idx = 0;
|
||||
|
||||
function refresh(parent) {
|
||||
var group, title;
|
||||
var id = parent.attr('id');
|
||||
if (parent.attr('data-group-id')) {
|
||||
group = parent.attr('data-group-id');
|
||||
title = parent.attr('data-name');
|
||||
}
|
||||
else {
|
||||
group = null;
|
||||
title = 'All Hosts'
|
||||
}
|
||||
// The following will trigger the host list to load. See Inventory.js controller.
|
||||
scope.$emit(emit_on_select, id, group, title);
|
||||
}
|
||||
|
||||
function activate(e) {
|
||||
/* Set the clicked node as active */
|
||||
var elm = angular.element(e.target); //<a>
|
||||
var parent = angular.element(e.target.parentNode.parentNode); //<li>
|
||||
$('.search-tree .active').removeClass('active');
|
||||
elm.parent().addClass('active'); // add active class to <div>
|
||||
refresh(parent);
|
||||
}
|
||||
|
||||
function toggle(e) {
|
||||
var id, parent, elm, icon;
|
||||
|
||||
if (e.target.tagName == 'I') {
|
||||
id = e.target.parentNode.parentNode.parentNode.attributes.id.value;
|
||||
parent = angular.element(e.target.parentNode.parentNode.parentNode); //<li>
|
||||
elm = angular.element(e.target.parentNode); // <a>
|
||||
}
|
||||
else {
|
||||
id = e.target.parentNode.parentNode.attributes.id.value;
|
||||
parent = angular.element(e.target.parentNode.parentNode);
|
||||
elm = angular.element(e.target);
|
||||
}
|
||||
|
||||
var sibling = angular.element(parent.children()[2]); // <a>
|
||||
var state = parent.attr('data-state');
|
||||
var icon = angular.element(elm.children()[0]);
|
||||
|
||||
if (state == 'closed') {
|
||||
// expand the elment
|
||||
var childlists = parent.find('ul');
|
||||
if (childlists && childlists.length > 0) {
|
||||
// has childen
|
||||
for (var i=0; i < childlists.length; i++) {
|
||||
var listChild = angular.element(childlists[i]);
|
||||
var listParent = angular.element(listChild.parent());
|
||||
if (listParent.attr('id') == id) {
|
||||
angular.element(childlists[i]).removeClass('hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
parent.attr('data-state','open');
|
||||
icon.removeClass('icon-caret-right').addClass('icon-caret-down');
|
||||
}
|
||||
else {
|
||||
// close the element
|
||||
parent.attr('data-state','closed');
|
||||
icon.removeClass('icon-caret-down').addClass('icon-caret-right');
|
||||
var childlists = parent.find('ul');
|
||||
var sublist, subicon;
|
||||
if (childlists && childlists.length > 0) {
|
||||
// has childen
|
||||
childlists.each(function(idx) {
|
||||
$(this).addClass('hidden');
|
||||
subicon = $(this).find('li').first().find('.expand-container i');
|
||||
subicon.removeClass('icon-caret-down').addClass('icon-caret-right');
|
||||
});
|
||||
}
|
||||
/* When the active node's parent is closed, activate the parent */
|
||||
if ($(parent).find('.active').length > 0) {
|
||||
$(parent).find('.active').removeClass('active');
|
||||
sibling.addClass('active');
|
||||
refresh(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (scope.moveNodeRemove) {
|
||||
scope.moveNodeRemove();
|
||||
}
|
||||
scope.moveNodeRemove = scope.$on('MoveNode', function(e, node, parent, target) {
|
||||
var inv_id = scope['inventory_id'];
|
||||
var variables;
|
||||
|
||||
function cleanUp(state) {
|
||||
/*
|
||||
if (state !== 'fail') {
|
||||
// Visually move the element. Elment will be appended to the
|
||||
// end of target element list
|
||||
var elm = $('#' + node.attr('id')).detach();
|
||||
if (target.find('ul').length > 0) {
|
||||
// parent has children
|
||||
target.find('ul').first().append(elm);
|
||||
}
|
||||
else {
|
||||
target.append('<ul></ul>');
|
||||
target.find('ul').first().append(elm);
|
||||
}
|
||||
|
||||
// Remove any styling that might be left on the target
|
||||
// and put the expander icon back the way it should be
|
||||
target.find('div').each(function(idx) {
|
||||
if (idx > 0 && idx < 3) {
|
||||
$(this).css({ 'border-bottom': '2px solid #f5f5f5' });
|
||||
}
|
||||
});
|
||||
|
||||
// Make sure the parent and target have the correct expander class/icon.
|
||||
function setExpander(n) {
|
||||
var c = n.find('.expand-container');
|
||||
var icon;
|
||||
c.first().empty();
|
||||
if (n.attr('id') == 'inventory-root-node') {
|
||||
c.first().html('<i class=\"icon-sitemap\"></i>');
|
||||
}
|
||||
else if (c.length > 1) {
|
||||
// not root and has children, put expander icon back
|
||||
icon = (n.attr('data-state') == 'opened') ? 'icon-caret-down' : 'icon-caret-right';
|
||||
c.first().html('<a class="expand"><i class="' + icon + '"></i></a>');
|
||||
c.first().find('a').first().bind('click', toggle);
|
||||
}
|
||||
}
|
||||
setExpander(target);
|
||||
setExpander(parent);
|
||||
}
|
||||
Wait('stop');
|
||||
*/
|
||||
// Reload the tree
|
||||
html = '';
|
||||
idx = 0;
|
||||
loadTreeData();
|
||||
}
|
||||
|
||||
// disassociate the group from the original parent
|
||||
if (scope.removeGroupRemove) {
|
||||
scope.removeGroupRemove();
|
||||
}
|
||||
scope.removeGroupRemove = scope.$on('removeGroup', function() {
|
||||
if (parent.attr('data-group-id')) {
|
||||
// Only remove a group from a parent when the parent is a group and not the inventory root
|
||||
var url = GetBasePath('base') + 'groups/' + parent.attr('data-group-id') + '/children/';
|
||||
Rest.setUrl(url);
|
||||
Rest.post({ id: node.attr('data-group-id'), disassociate: 1 })
|
||||
.success( function(data, status, headers, config) {
|
||||
cleanUp('success');
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
cleanUp('fail');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to remove ' + node.attr('name') + ' from ' +
|
||||
parent.attr('name') + '. POST returned status: ' + status });
|
||||
});
|
||||
}
|
||||
else {
|
||||
cleanUp('success');
|
||||
}
|
||||
});
|
||||
|
||||
if (scope['addToTargetRemove']) {
|
||||
scope.addToTargetRemove();
|
||||
}
|
||||
scope.addToTargetRemove = scope.$on('addToTarget', function() {
|
||||
// add the new group to the target parent
|
||||
var url = (target.attr('data-group-id')) ? GetBasePath('base') + 'groups/' + target.attr('data-group-id') + '/children/' :
|
||||
GetBasePath('inventory') + inv_id + '/groups/';
|
||||
var group = {
|
||||
id: node.attr('data-group-id'),
|
||||
name: node.attr('data-name'),
|
||||
description: node.attr('data-description'),
|
||||
inventory: inv_id
|
||||
}
|
||||
Rest.setUrl(url);
|
||||
Rest.post(group)
|
||||
.success( function(data, status, headers, config) {
|
||||
scope.$emit('removeGroup');
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
cleanUp('fail');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to add ' + node.attr('name') + ' to ' +
|
||||
target.attr('name') + '. POST returned status: ' + status });
|
||||
});
|
||||
});
|
||||
|
||||
Wait('start');
|
||||
// Lookup the inventory. We already have what we need except for variables.
|
||||
var url = GetBasePath('base') + 'groups/' + node.attr('data-group-id') + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
variables = (data.variables) ? JSON.parse(data.variables) : "";
|
||||
scope.$emit('addToTarget');
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
cleanUp('fail');
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to lookup group ' + node.attr('name') +
|
||||
'. GET returned status: ' + status });
|
||||
});
|
||||
});
|
||||
|
||||
// The HTML is ready. Insert it into the view.
|
||||
if (scope.searchTreeReadyRemove) {
|
||||
scope.searchTreeReadyRemove();
|
||||
}
|
||||
scope.searchTreeReadyRemove = scope.$on('searchTreeReady', function(e, html) {
|
||||
|
||||
var container = angular.element(document.getElementById(target_id));
|
||||
container.empty();
|
||||
var compiled = $compile(html)(scope);
|
||||
container.append(compiled);
|
||||
|
||||
function setTitleWidth(elm) {
|
||||
// Fix for overflowing title text
|
||||
var container = $('#search-tree-target');
|
||||
var container_offset = container.offset();
|
||||
var parent = elm.parent(); // <li>
|
||||
var parent_offset = parent.offset();
|
||||
var expander = parent.find('.expand-container').first();
|
||||
var badge = parent.find('.badge-container').first();
|
||||
var width = container.width() - parent_offset.left + container_offset.left -
|
||||
badge.width() - expander.width() - 10;
|
||||
elm.css('width', width + 'px');
|
||||
}
|
||||
|
||||
// Fix overflowing title text now
|
||||
$('#' + target_id).find('.title-container').each(function(idx) {
|
||||
setTitleWidth($(this));
|
||||
});
|
||||
|
||||
// Fix overflowing title text on screen resize
|
||||
var timeout;
|
||||
$(window).resize(function() {
|
||||
clearTimeout(timeout); //remove prior timer so we don't resize a million times
|
||||
timeout = setTimeout(function() {
|
||||
$('#' + target_id).find('.title-container').each(function(idx) {
|
||||
setTitleWidth($(this));
|
||||
});
|
||||
}, 500);
|
||||
});
|
||||
|
||||
var links = container.find('a');
|
||||
for (var i=0; i < links.length; i++) {
|
||||
var link = angular.element(links[i]);
|
||||
if (link.hasClass('expand')) {
|
||||
link.unbind('click', toggle);
|
||||
link.bind('click', toggle);
|
||||
}
|
||||
if (link.hasClass('activate')) {
|
||||
link.unbind('click', activate);
|
||||
link.bind('click', activate);
|
||||
}
|
||||
}
|
||||
|
||||
if (refresh_tree && group_id !== undefined) {
|
||||
// pick a node by group_id
|
||||
$('li[data-group-id="' + group_id + '"] .activate').first().click();
|
||||
}
|
||||
else if (refresh_tree && id !== undefined) {
|
||||
// pick a node by id
|
||||
$('#' + id + ' .activate').first().click();
|
||||
}
|
||||
else if (!refresh_tree) {
|
||||
// default to the root node
|
||||
$('#inventory-root-node .activate').first().click();
|
||||
}
|
||||
|
||||
// Make the tree drag-n-droppable
|
||||
if (moveable) {
|
||||
$('#selector-tree .activate').draggable({
|
||||
cursor: "pointer",
|
||||
cursorAt: { top: -16, left: -10 },
|
||||
revert: 'invalid',
|
||||
helper: 'clone',
|
||||
start: function (e, ui) {
|
||||
var txt = '[ ' + ui.helper.text() + ' ]';
|
||||
ui.helper.css({ 'display': 'inline-block', 'font-weight': 'normal', 'color': '#171717',
|
||||
'background-color': '#f5f5f5', 'overflow': 'visible', 'white-space': 'normal',
|
||||
'z-index': 5000 }).text(txt);
|
||||
}
|
||||
})
|
||||
.droppable({
|
||||
//hoverClass: 'droppable-hover',
|
||||
tolerance: 'pointer',
|
||||
over: function (e, ui) {
|
||||
var p = $(this).parent().parent();
|
||||
p.find('div').each(function(idx) {
|
||||
if (idx > 0 && idx < 3) {
|
||||
$(this).css({ 'border-bottom': '2px solid #171717' });
|
||||
}
|
||||
});
|
||||
var c = p.find('.expand-container').first();
|
||||
c.empty().html('<i class="icon-circle-arrow-right" style="color: #171717;"></i>');
|
||||
},
|
||||
out: function (e, ui) {
|
||||
var p = $(this).parent().parent();
|
||||
p.find('div').each(function(idx) {
|
||||
if (idx > 0 && idx < 3) {
|
||||
$(this).css({ 'border-bottom': '2px solid #f5f5f5' });
|
||||
}
|
||||
});
|
||||
var c = p.find('.expand-container');
|
||||
var icon;
|
||||
c.first().empty();
|
||||
if (c.length > 1) {
|
||||
// has children, put expander icon back
|
||||
icon = (p.attr('data-state') == 'opened') ? 'icon-caret-down' : 'icon-caret-right';
|
||||
c.first().html('<a class="expand"><i class="' + icon + '"></i></a>');
|
||||
c.first().find('a').first().bind('click', toggle);
|
||||
}
|
||||
},
|
||||
drop: function (e,ui) {
|
||||
var variables;
|
||||
var node = ui.draggable.parent().parent(); // node being moved
|
||||
var parent = node.parent().parent(); // node from
|
||||
var target = $(this).parent().parent(); // node to
|
||||
scope.$emit('MoveNode', node, parent, target);
|
||||
|
||||
// Make sure angular picks up changes and jQuery doesn't
|
||||
// leave us in limbo...
|
||||
if (!scope.$$phase) {
|
||||
scope.$digest();
|
||||
}
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
} // if moveable
|
||||
|
||||
Wait('stop');
|
||||
});
|
||||
|
||||
function buildHTML(tree_data) {
|
||||
var sorted = SortNodes(tree_data);
|
||||
var toolTip;
|
||||
|
||||
html += (sorted.length > 0) ? "<ul>\n" : "";
|
||||
for(var i=0; i < sorted.length; i++) {
|
||||
html += "<li id=\"search-node-0" + idx + "\" data-state=\"opened\" data-hosts=\"" + sorted[i].related.hosts + "\" " +
|
||||
"data-description=\"" + sorted[i].description + "\" " +
|
||||
"data-failures=\"" + sorted[i].has_active_failures + "\" " +
|
||||
"data-groups=\"" + sorted[i].related.groups + "\" " +
|
||||
"data-name=\"" + sorted[i].name + "\" " +
|
||||
"data-group-id=\"" + sorted[i].id + "\" " +
|
||||
"><div class=\"expand-container\">";
|
||||
|
||||
if (sorted[i].children.length > 0) {
|
||||
html += "<a href=\"\" class=\"expand\"><i class=\"icon-caret-down\"></i></a>";
|
||||
}
|
||||
else {
|
||||
html += " ";
|
||||
}
|
||||
html += "</div>";
|
||||
|
||||
toolTip = GetToolTip({ node: sorted[i] });
|
||||
|
||||
html += "<div class=\"badge-container\">";
|
||||
html += "<a aw-tool-tip=\"" + toolTip.tooltip + "\" data-placement=\"top\"";
|
||||
html += (toolTip.url !== '') ? " href=\"" + toolTip.url + "\"": "";
|
||||
html += ">";
|
||||
html += "<i class=\"field-badge icon-failures-" + toolTip['class'] + "\" ></i>";
|
||||
html += "</a>";
|
||||
html += "</div> ";
|
||||
|
||||
html += "<div class=\"title-container\"><a class=\"activate\">" + sorted[i].name + "</a></div>";
|
||||
|
||||
idx++;
|
||||
if (sorted[i].children.length > 0) {
|
||||
buildHTML(sorted[i].children);
|
||||
}
|
||||
else {
|
||||
//html += "<ul></ul>\n";
|
||||
html += "</li>\n";
|
||||
}
|
||||
}
|
||||
html += "</ul>\n";
|
||||
}
|
||||
|
||||
// Build the HTML for our tree
|
||||
if (scope.buildAllGroupsRemove) {
|
||||
scope.buildAllGroupsRemove();
|
||||
}
|
||||
scope.buildAllGroupsRemove = scope.$on('buildAllGroups', function(e, inventory_name, inventory_tree) {
|
||||
Rest.setUrl(inventory_tree);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
buildHTML(data);
|
||||
scope.$emit('searchTreeReady', html + "</li>\n</ul>\n</div>\n");
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to get inventory tree for: ' + inventory_id + '. GET returned: ' + status });
|
||||
});
|
||||
});
|
||||
|
||||
// Builds scope.inventory_groups, used by the group picker on Hosts view to build the list of potential groups
|
||||
// that can be added to a host. <<<< Should probably be moved to /helpers/Hosts.js
|
||||
if (scope.buildGroupListRemove) {
|
||||
scope.buildGroupListRemove();
|
||||
}
|
||||
scope.buildGroupListRemove = scope.$on('buildAllGroups', function(e, inventory_name, inventory_tree, groups_url) {
|
||||
scope.inventory_groups = [];
|
||||
Rest.setUrl(groups_url);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
var groups = [];
|
||||
for (var i=0; i < data.results.length; i++) {
|
||||
groups.push({
|
||||
id: data.results[i].id,
|
||||
description: data.results[i].description,
|
||||
name: data.results[i].name });
|
||||
}
|
||||
scope.inventory_groups = SortNodes(groups);
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to get groups for inventory: ' + inventory_id + '. GET returned: ' + status });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function loadTreeData() {
|
||||
// Load the inventory root node
|
||||
Wait('start');
|
||||
Rest.setUrl (GetBasePath('inventory') + inventory_id + '/');
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
|
||||
var tip = GetInventoryToolTip({ node: data });
|
||||
|
||||
html += "<div class=\"title\">Group Selector:</div>\n" +
|
||||
"<div id=\"selector-tree\">\n" +
|
||||
"<ul id=\"inventory-tree\" class=\"tree-root\">\n" +
|
||||
"<li id=\"inventory-root-node\" data-state=\"opened\" data-hosts=\"" + data.related.hosts + "\" " +
|
||||
"data-description=\"" + data.description + "\" " +
|
||||
"data-failures=\"" + data.has_active_failures + "\" " +
|
||||
"data-groups=\"" + data.related.groups + "\" " +
|
||||
"data-name=\"" + data.name + "\" " +
|
||||
"data-inventory=\"" + data.id + "\"" +
|
||||
">" +
|
||||
"<div class=\"expand-container\" id=\"root-expand-container\"><i class=\"icon-sitemap\"></i></div>" +
|
||||
"<div class=\"badge-container\" id=\"root-badge-container\">\n";
|
||||
|
||||
html += "<a aw-tool-tip=\"" + tip['tooltip'] + "\" data-placement=\"top\"";
|
||||
html += (tip.link) ? " href=\"" + tip['link'] + "\"" : "";
|
||||
html += ">";
|
||||
html += "<i class=\"field-badge icon-failures-" + tip['class'] + "\"></i></a>";
|
||||
html += "</div>\n";
|
||||
|
||||
html += "<div class=\"title-container\" id=\"root-title-container\">" +
|
||||
"<a class=\"activate\">" + data.name + "</a></div>";
|
||||
|
||||
scope.$emit('buildAllGroups', data.name, data.related.tree, data.related.groups);
|
||||
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to get inventory: ' + inventory_id + '. GET returned: ' + status });
|
||||
});
|
||||
}
|
||||
|
||||
loadTreeData();
|
||||
|
||||
}
|
||||
}])
|
||||
|
||||
// Set node name and description after an update to Group properties.
|
||||
.factory('SetNodeName', [ function() {
|
||||
return function(params) {
|
||||
var scope = params.scope;
|
||||
var name = params.name;
|
||||
var descr = params.description;
|
||||
var group_id = (params.group_id !== undefined) ? params.group_id : null;
|
||||
var inventory_id = (params.inventory_id != undefined) ? params.inventory_id : null;
|
||||
|
||||
if (group_id !== null) {
|
||||
$('#inventory-tree').find('li [data-group-id="' + group_id + '"]').each(function(idx) {
|
||||
$(this).attr('data-name',name);
|
||||
$(this).attr('data-description',descr);
|
||||
$(this).find('.activate').first().text(name);
|
||||
});
|
||||
}
|
||||
|
||||
if (inventory_id !== null) {
|
||||
$('#inventory-root-node').attr('data-name', name).attr('data-description', descr).find('.activate').first().text(name);
|
||||
}
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('ClickNode', [ function() {
|
||||
return function(params) {
|
||||
var selector = params.selector; //jquery selector string to find the correct <li>
|
||||
$(selector + ' .activate').first().click();
|
||||
}
|
||||
}])
|
||||
|
||||
.factory('DeleteNode', [ function() {
|
||||
return function(params) {
|
||||
var selector = params.selector; //jquery selector string to find the correct <li>
|
||||
$(selector).first().detach();
|
||||
}
|
||||
}]);
|
||||
@ -10,68 +10,72 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
|
||||
.factory('ClearScope', [ function() {
|
||||
return function(id) {
|
||||
|
||||
var element = document.getElementById(id), scope;
|
||||
angular.module('Utilities', ['RestServices', 'Utilities'])
|
||||
|
||||
.factory('ClearScope', [
|
||||
function () {
|
||||
return function (id) {
|
||||
|
||||
var element = document.getElementById(id),
|
||||
scope;
|
||||
if (element) {
|
||||
scope = angular.element(element).scope();
|
||||
scope.$destroy();
|
||||
}
|
||||
|
||||
$('.tooltip').each( function() {
|
||||
$('.tooltip').each(function () {
|
||||
// Remove any lingering tooltip and popover <div> elements
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
$('.popover').each(function() {
|
||||
$('.popover').each(function () {
|
||||
// remove lingering popover <div>. Seems to be a bug in TB3 RC1
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
try {
|
||||
$('#help-modal').dialog('close');
|
||||
}
|
||||
catch(e) {
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
$(window).unbind('resize');
|
||||
|
||||
};
|
||||
}])
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
/* Empty()
|
||||
*
|
||||
* Test if a value is 'empty'. Returns true if val is null | '' | undefined.
|
||||
* Only works on non-Ojbect types.
|
||||
*
|
||||
*/
|
||||
.factory('Empty', [ function() {
|
||||
return function(val) {
|
||||
|
||||
/* Empty()
|
||||
*
|
||||
* Test if a value is 'empty'. Returns true if val is null | '' | undefined.
|
||||
* Only works on non-Ojbect types.
|
||||
*
|
||||
*/
|
||||
.factory('Empty', [
|
||||
function () {
|
||||
return function (val) {
|
||||
return (val === null || val === undefined || val === '') ? true : false;
|
||||
};
|
||||
}])
|
||||
|
||||
|
||||
.factory('ToggleClass', function() {
|
||||
return function(selector, cssClass) {
|
||||
// Toggles the existance of a css class on a given element
|
||||
if ( $(selector) && $(selector).hasClass(cssClass) ) {
|
||||
$(selector).removeClass(cssClass);
|
||||
}
|
||||
else if ($(selector)) {
|
||||
$(selector).addClass(cssClass);
|
||||
}
|
||||
};
|
||||
})
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
.factory('Alert', ['$rootScope', function($rootScope) {
|
||||
return function(hdr, msg, cls, action, secondAlert, disableButtons) {
|
||||
.factory('ToggleClass', function () {
|
||||
return function (selector, cssClass) {
|
||||
// Toggles the existance of a css class on a given element
|
||||
if ($(selector) && $(selector).hasClass(cssClass)) {
|
||||
$(selector).removeClass(cssClass);
|
||||
} else if ($(selector)) {
|
||||
$(selector).addClass(cssClass);
|
||||
}
|
||||
};
|
||||
})
|
||||
|
||||
|
||||
.factory('Alert', ['$rootScope',
|
||||
function ($rootScope) {
|
||||
return function (hdr, msg, cls, action, secondAlert, disableButtons) {
|
||||
// Pass in the header and message you want displayed on TB modal dialog found in index.html.
|
||||
// Assumes an #id of 'alert-modal'. Pass in an optional TB alert class (i.e. alert-danger, alert-success,
|
||||
// alert-info...). Pass an optional function(){}, if you want a specific action to occur when user
|
||||
@ -79,15 +83,19 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
if (secondAlert) {
|
||||
$rootScope.alertHeader2 = hdr;
|
||||
$rootScope.alertBody2 = msg;
|
||||
$rootScope.alertClass2 = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger
|
||||
$('#alert-modal2').modal({ show: true, keyboard: true , backdrop: 'static' });
|
||||
$rootScope.alertClass2 = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger
|
||||
$('#alert-modal2').modal({
|
||||
show: true,
|
||||
keyboard: true,
|
||||
backdrop: 'static'
|
||||
});
|
||||
$rootScope.disableButtons2 = (disableButtons) ? true : false;
|
||||
if (action) {
|
||||
$('#alert-modal2').on('hidden', function() {
|
||||
$('#alert-modal2').on('hidden', function () {
|
||||
action();
|
||||
});
|
||||
}
|
||||
$(document).bind('keydown', function(e) {
|
||||
$(document).bind('keydown', function (e) {
|
||||
if (e.keyCode === 27) {
|
||||
$('#alert-modal2').modal('hide');
|
||||
if (action) {
|
||||
@ -95,14 +103,17 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$rootScope.alertHeader = hdr;
|
||||
$rootScope.alertBody = msg;
|
||||
$rootScope.alertClass = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger
|
||||
$('#alert-modal').modal({ show: true, keyboard: true , backdrop: 'static' });
|
||||
|
||||
$(document).bind('keydown', function(e) {
|
||||
$rootScope.alertClass = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger
|
||||
$('#alert-modal').modal({
|
||||
show: true,
|
||||
keyboard: true,
|
||||
backdrop: 'static'
|
||||
});
|
||||
|
||||
$(document).bind('keydown', function (e) {
|
||||
if (e.keyCode === 27) {
|
||||
$('#alert-modal').modal('hide');
|
||||
if (action) {
|
||||
@ -113,168 +124,171 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
|
||||
$rootScope.disableButtons = (disableButtons) ? true : false;
|
||||
if (action) {
|
||||
$('#alert-modal').on('hidden', function() {
|
||||
$('#alert-modal').on('hidden', function () {
|
||||
action();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}])
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
.factory('ProcessErrors', ['$rootScope', '$cookieStore', '$log', '$location', 'Alert', 'Wait',
|
||||
function($rootScope, $cookieStore, $log, $location, Alert, Wait) {
|
||||
return function(scope, data, status, form, defaultMsg) {
|
||||
var field, fieldErrors, msg;
|
||||
Wait('stop');
|
||||
if ($AnsibleConfig.debug_mode && console) {
|
||||
console.log('Debug status: ' + status);
|
||||
console.log('Debug data: ');
|
||||
console.log(data);
|
||||
.factory('ProcessErrors', ['$rootScope', '$cookieStore', '$log', '$location', 'Alert', 'Wait',
|
||||
function ($rootScope, $cookieStore, $log, $location, Alert, Wait) {
|
||||
return function (scope, data, status, form, defaultMsg) {
|
||||
var field, fieldErrors, msg;
|
||||
Wait('stop');
|
||||
if ($AnsibleConfig.debug_mode && console) {
|
||||
console.log('Debug status: ' + status);
|
||||
console.log('Debug data: ');
|
||||
console.log(data);
|
||||
}
|
||||
if (status === 403) {
|
||||
msg = 'The API responded with a 403 Access Denied error. ';
|
||||
if (data.detail) {
|
||||
msg += 'Detail: ' + data.detail;
|
||||
} else {
|
||||
msg += 'Please contact your system administrator.';
|
||||
}
|
||||
if (status === 403) {
|
||||
msg = 'The API responded with a 403 Access Denied error. ';
|
||||
if (data.detail) {
|
||||
msg += 'Detail: ' + data.detail;
|
||||
Alert(defaultMsg.hdr, msg);
|
||||
} else if ((status === 401 && data.detail && data.detail === 'Token is expired') ||
|
||||
(status === 401 && data.detail && data.detail === 'Invalid token')) {
|
||||
$rootScope.sessionTimer.expireSession();
|
||||
$location.url('/login');
|
||||
} else if (data.non_field_errors) {
|
||||
Alert('Error!', data.non_field_errors);
|
||||
} else if (data.detail) {
|
||||
Alert(defaultMsg.hdr, defaultMsg.msg + ' ' + data.detail);
|
||||
} else if (data.__all__) {
|
||||
Alert('Error!', data.__all__);
|
||||
} else if (form) {
|
||||
fieldErrors = false;
|
||||
for (field in form.fields) {
|
||||
if (data[field] && form.fields[field].tab) {
|
||||
// If the form is part of a tab group, activate the tab
|
||||
$('#' + form.name + "_tabs a[href=\"#" + form.fields[field].tab + '"]').tab('show');
|
||||
}
|
||||
else {
|
||||
msg += 'Please contact your system administrator.';
|
||||
}
|
||||
Alert(defaultMsg.hdr, msg);
|
||||
}
|
||||
else if ( (status === 401 && data.detail && data.detail === 'Token is expired') ||
|
||||
(status === 401 && data.detail && data.detail === 'Invalid token') ) {
|
||||
$rootScope.sessionTimer.expireSession();
|
||||
$location.url('/login');
|
||||
}
|
||||
else if (data.non_field_errors) {
|
||||
Alert('Error!', data.non_field_errors);
|
||||
}
|
||||
else if (data.detail) {
|
||||
Alert(defaultMsg.hdr, defaultMsg.msg + ' ' + data.detail);
|
||||
}
|
||||
else if (data.__all__) {
|
||||
Alert('Error!', data.__all__);
|
||||
}
|
||||
else if (form) {
|
||||
fieldErrors = false;
|
||||
for (field in form.fields ) {
|
||||
if (data[field] && form.fields[field].tab) {
|
||||
// If the form is part of a tab group, activate the tab
|
||||
$('#' + form.name + "_tabs a[href=\"#" + form.fields[field].tab + '"]').tab('show');
|
||||
}
|
||||
if (form.fields[field].realName) {
|
||||
if (data[form.fields[field].realName]) {
|
||||
scope[field + '_api_error'] = data[form.fields[field]][0];
|
||||
//scope[form.name + '_form'][form.fields[field].realName].$setValidity('apiError', false);
|
||||
$('[name="' + form.fields[field].realName + '"]').addClass('ng-invalid');
|
||||
fieldErrors = true;
|
||||
}
|
||||
}
|
||||
if (form.fields[field].sourceModel) {
|
||||
if (data[field]) {
|
||||
scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '_api_error'] =
|
||||
data[field][0];
|
||||
//scope[form.name + '_form'][form.fields[field].sourceModel + '_' + form.fields[field].sourceField].$setValidity('apiError', false);
|
||||
$('[name="' + form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '"]').addClass('ng-invalid');
|
||||
fieldErrors = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (data[field]) {
|
||||
scope[field + '_api_error'] = data[field][0];
|
||||
//scope[form.name + '_form'][field].$setValidity('apiError', false);
|
||||
$('[name="' + field + '"]').addClass('ng-invalid');
|
||||
fieldErrors = true;
|
||||
}
|
||||
if (form.fields[field].realName) {
|
||||
if (data[form.fields[field].realName]) {
|
||||
scope[field + '_api_error'] = data[form.fields[field]][0];
|
||||
//scope[form.name + '_form'][form.fields[field].realName].$setValidity('apiError', false);
|
||||
$('[name="' + form.fields[field].realName + '"]').addClass('ng-invalid');
|
||||
fieldErrors = true;
|
||||
}
|
||||
}
|
||||
if ((!fieldErrors) && defaultMsg) {
|
||||
Alert(defaultMsg.hdr, defaultMsg.msg);
|
||||
if (form.fields[field].sourceModel) {
|
||||
if (data[field]) {
|
||||
scope[form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '_api_error'] =
|
||||
data[field][0];
|
||||
//scope[form.name + '_form'][form.fields[field].sourceModel + '_' + form.fields[field].sourceField].$setValidity('apiError', false);
|
||||
$('[name="' + form.fields[field].sourceModel + '_' + form.fields[field].sourceField + '"]').addClass('ng-invalid');
|
||||
fieldErrors = true;
|
||||
}
|
||||
} else {
|
||||
if (data[field]) {
|
||||
scope[field + '_api_error'] = data[field][0];
|
||||
//scope[form.name + '_form'][field].$setValidity('apiError', false);
|
||||
$('[name="' + field + '"]').addClass('ng-invalid');
|
||||
fieldErrors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((!fieldErrors) && defaultMsg) {
|
||||
Alert(defaultMsg.hdr, defaultMsg.msg);
|
||||
}
|
||||
};
|
||||
}])
|
||||
} else {
|
||||
Alert(defaultMsg.hdr, defaultMsg.msg);
|
||||
}
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
.factory('LoadBreadCrumbs', ['$rootScope', '$routeParams', '$location', 'Empty',
|
||||
function($rootScope, $routeParams, $location, Empty) {
|
||||
return function(crumb) {
|
||||
|
||||
var title, found, j, i, paths, ppath, parent, child;
|
||||
|
||||
function toUppercase(a) {
|
||||
return a.toUpperCase();
|
||||
}
|
||||
|
||||
function singular(a) {
|
||||
return (a === 'ies') ? 'y' : '';
|
||||
}
|
||||
|
||||
//Keep a list of path/title mappings. When we see /organizations/XX in the path, for example,
|
||||
//we'll know the actual organization name it maps to.
|
||||
if (!Empty(crumb)) {
|
||||
found = false;
|
||||
//crumb.title = crumb.title.charAt(0).toUpperCase() + crumb.title.slice(1);
|
||||
for (i=0; i < $rootScope.crumbCache.length; i++) {
|
||||
if ($rootScope.crumbCache[i].path === crumb.path) {
|
||||
found = true;
|
||||
$rootScope.crumbCache[i] = crumb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
$rootScope.crumbCache.push(crumb);
|
||||
.factory('LoadBreadCrumbs', ['$rootScope', '$routeParams', '$location', 'Empty',
|
||||
function ($rootScope, $routeParams, $location, Empty) {
|
||||
return function (crumb) {
|
||||
|
||||
var title, found, j, i, paths, ppath, parent, child;
|
||||
|
||||
function toUppercase(a) {
|
||||
return a.toUpperCase();
|
||||
}
|
||||
|
||||
function singular(a) {
|
||||
return (a === 'ies') ? 'y' : '';
|
||||
}
|
||||
|
||||
//Keep a list of path/title mappings. When we see /organizations/XX in the path, for example,
|
||||
//we'll know the actual organization name it maps to.
|
||||
if (!Empty(crumb)) {
|
||||
found = false;
|
||||
//crumb.title = crumb.title.charAt(0).toUpperCase() + crumb.title.slice(1);
|
||||
for (i = 0; i < $rootScope.crumbCache.length; i++) {
|
||||
if ($rootScope.crumbCache[i].path === crumb.path) {
|
||||
found = true;
|
||||
$rootScope.crumbCache[i] = crumb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
paths = $location.path().replace(/^\//,'').split('/');
|
||||
ppath = '';
|
||||
$rootScope.breadcrumbs = [];
|
||||
if (paths.length > 1) {
|
||||
for (i=0; i < paths.length - 1; i++) {
|
||||
if (i > 0 && paths[i].match(/\d+/)) {
|
||||
parent = paths[i-1];
|
||||
child = parent.replace(/(ies$|s$)/, singular);
|
||||
child = child.charAt(0).toUpperCase() + child.slice(1);
|
||||
// find the correct title
|
||||
found = false;
|
||||
for (j=0; j < $rootScope.crumbCache.length; j++) {
|
||||
if ($rootScope.crumbCache[j].path === '/' + parent + '/' + paths[i]) {
|
||||
child = $rootScope.crumbCache[j].title;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found && $rootScope.crumbCache[j].altPath !== undefined) {
|
||||
// Use altPath to override default path construction
|
||||
$rootScope.breadcrumbs.push({ title: child, path: $rootScope.crumbCache[j].altPath });
|
||||
}
|
||||
else {
|
||||
$rootScope.breadcrumbs.push({ title: child, path: ppath + '/' + paths[i] });
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (/_/.test(paths[i])) {
|
||||
// replace '_' with space and uppercase each word
|
||||
paths[i] = paths[i].replace(/(?:^|_)\S/g, toUppercase)
|
||||
.replace(/_/g,' ');
|
||||
}
|
||||
title = paths[i].charAt(0).toUpperCase() + paths[i].slice(1);
|
||||
$rootScope.breadcrumbs.push({ title: title, path: ppath + '/' + paths[i] });
|
||||
}
|
||||
ppath += '/' + paths[i];
|
||||
}
|
||||
if (!found) {
|
||||
$rootScope.crumbCache.push(crumb);
|
||||
}
|
||||
};
|
||||
}])
|
||||
|
||||
.factory('HelpDialog', ['$rootScope', '$location', 'Store', function($rootScope, $location, Store) {
|
||||
return function(params) {
|
||||
}
|
||||
|
||||
paths = $location.path().replace(/^\//, '').split('/');
|
||||
ppath = '';
|
||||
$rootScope.breadcrumbs = [];
|
||||
if (paths.length > 1) {
|
||||
for (i = 0; i < paths.length - 1; i++) {
|
||||
if (i > 0 && paths[i].match(/\d+/)) {
|
||||
parent = paths[i - 1];
|
||||
child = parent.replace(/(ies$|s$)/, singular);
|
||||
child = child.charAt(0).toUpperCase() + child.slice(1);
|
||||
// find the correct title
|
||||
found = false;
|
||||
for (j = 0; j < $rootScope.crumbCache.length; j++) {
|
||||
if ($rootScope.crumbCache[j].path === '/' + parent + '/' + paths[i]) {
|
||||
child = $rootScope.crumbCache[j].title;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found && $rootScope.crumbCache[j].altPath !== undefined) {
|
||||
// Use altPath to override default path construction
|
||||
$rootScope.breadcrumbs.push({
|
||||
title: child,
|
||||
path: $rootScope.crumbCache[j].altPath
|
||||
});
|
||||
} else {
|
||||
$rootScope.breadcrumbs.push({
|
||||
title: child,
|
||||
path: ppath + '/' + paths[i]
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (/_/.test(paths[i])) {
|
||||
// replace '_' with space and uppercase each word
|
||||
paths[i] = paths[i].replace(/(?:^|_)\S/g, toUppercase)
|
||||
.replace(/_/g, ' ');
|
||||
}
|
||||
title = paths[i].charAt(0).toUpperCase() + paths[i].slice(1);
|
||||
$rootScope.breadcrumbs.push({
|
||||
title: title,
|
||||
path: ppath + '/' + paths[i]
|
||||
});
|
||||
}
|
||||
ppath += '/' + paths[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
])
|
||||
|
||||
.factory('HelpDialog', ['$rootScope', '$location', 'Store',
|
||||
function ($rootScope, $location, Store) {
|
||||
return function (params) {
|
||||
// Display a help dialog
|
||||
//
|
||||
// HelpDialog({ defn: <HelpDefinition> })
|
||||
@ -285,10 +299,10 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
autoShow = params.autoShow || false;
|
||||
|
||||
function showHelp(step) {
|
||||
|
||||
var btns, ww, width, height, isOpen=false;
|
||||
|
||||
var btns, ww, width, height, isOpen = false;
|
||||
current_step = step;
|
||||
|
||||
|
||||
function buildHtml(step) {
|
||||
var html = '';
|
||||
//html += (step.intro) ? "<div class=\"help-intro\">" + step.intro + "</div>" : "";
|
||||
@ -301,7 +315,7 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
"name=\"auto-off-checkbox\" id=\"auto-off-checkbox\"> Do not show this message in the future</label></div>\n" : "";
|
||||
return html;
|
||||
}
|
||||
|
||||
|
||||
width = (defn.story.width) ? defn.story.width : 510;
|
||||
height = (defn.story.height) ? defn.story.height : 600;
|
||||
|
||||
@ -311,21 +325,19 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
|
||||
try {
|
||||
isOpen = $('#help-modal').dialog('isOpen');
|
||||
}
|
||||
catch(e) {
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
if (isOpen) {
|
||||
$('#help-modal').html(buildHtml(defn.story.steps[current_step]));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Define buttons based on story length
|
||||
btns = [];
|
||||
if (defn.story.steps.length > 1) {
|
||||
btns.push({
|
||||
text: "Prev",
|
||||
click: function(e) {
|
||||
click: function (e) {
|
||||
if (current_step - 1 === 0) {
|
||||
$(e.target).button('disable');
|
||||
}
|
||||
@ -338,7 +350,7 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
});
|
||||
btns.push({
|
||||
text: "Next",
|
||||
click: function(e) {
|
||||
click: function (e) {
|
||||
if (current_step + 1 > 0) {
|
||||
$(e.target).prev().button('enable');
|
||||
}
|
||||
@ -349,12 +361,19 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
}
|
||||
});
|
||||
}
|
||||
btns.push({ text: "Close",
|
||||
click: function() { $('#help-modal').dialog('close'); }
|
||||
btns.push({
|
||||
text: "Close",
|
||||
click: function () {
|
||||
$('#help-modal').dialog('close');
|
||||
}
|
||||
});
|
||||
// Show the dialog
|
||||
$('#help-modal').html(buildHtml(defn.story.steps[current_step])).dialog({
|
||||
position: { my: "center top", at: "center top+150", of: 'body' },
|
||||
position: {
|
||||
my: "center top",
|
||||
at: "center top+150",
|
||||
of: 'body'
|
||||
},
|
||||
title: defn.story.hdr,
|
||||
width: width,
|
||||
height: height,
|
||||
@ -363,75 +382,91 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
show: 500,
|
||||
hide: 500,
|
||||
resizable: false,
|
||||
close: function() { $('#help-modal').empty(); }
|
||||
close: function () {
|
||||
$('#help-modal').empty();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Make the buttons look like TB and add FA icons
|
||||
$('.ui-dialog-buttonset button').each( function() {
|
||||
$('.ui-dialog-buttonset button').each(function () {
|
||||
var c, h, l;
|
||||
l = $(this).text();
|
||||
if (l === 'Close') {
|
||||
h = "fa-times";
|
||||
c = "btn btn-default";
|
||||
$(this).attr({ 'class': c }).html("<i class=\"fa " + h + "\"></i> Close");
|
||||
}
|
||||
else if (l === 'Prev') {
|
||||
$(this).attr({
|
||||
'class': c
|
||||
}).html("<i class=\"fa " + h + "\"></i> Close");
|
||||
} else if (l === 'Prev') {
|
||||
h = "fa-chevron-left";
|
||||
c = "btn btn-primary";
|
||||
$(this).attr({ 'class': c }).html("<i class=\"fa " + h + "\"></i> Prev");
|
||||
}
|
||||
else {
|
||||
$(this).attr({
|
||||
'class': c
|
||||
}).html("<i class=\"fa " + h + "\"></i> Prev");
|
||||
} else {
|
||||
h = "fa-chevron-right";
|
||||
c = "btn btn-primary";
|
||||
$(this).attr({ 'class': c }).html("Next <i class=\"fa " + h + "\"></i>").css({ 'margin-right': '20px'});
|
||||
$(this).attr({
|
||||
'class': c
|
||||
}).html("Next <i class=\"fa " + h + "\"></i>").css({
|
||||
'margin-right': '20px'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('.ui-dialog[aria-describedby="help-modal"]').find('.ui-dialog-titlebar button')
|
||||
.empty().attr({ 'class': 'close' }).text('x');
|
||||
|
||||
.empty().attr({
|
||||
'class': 'close'
|
||||
}).text('x');
|
||||
|
||||
// If user clicks the checkbox, update local storage
|
||||
$('#auto-off-checkbox').click(function() {
|
||||
$('#auto-off-checkbox').click(function () {
|
||||
if ($('input[name="auto-off-checkbox"]:checked').length) {
|
||||
Store('inventoryAutoHelp','off');
|
||||
}
|
||||
else {
|
||||
Store('inventoryAutoHelp','on');
|
||||
Store('inventoryAutoHelp', 'off');
|
||||
} else {
|
||||
Store('inventoryAutoHelp', 'on');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
showHelp(0);
|
||||
|
||||
};
|
||||
}])
|
||||
}
|
||||
])
|
||||
|
||||
.factory('ReturnToCaller', ['$location', 'Empty', function($location, Empty) {
|
||||
return function(idx) {
|
||||
.factory('ReturnToCaller', ['$location', 'Empty',
|
||||
function ($location, Empty) {
|
||||
return function (idx) {
|
||||
// Split the current path by '/' and use the array elements from 0 up to and
|
||||
// including idx as the new path. If no idx value supplied, use 0 to length - 1.
|
||||
|
||||
var paths = $location.path().replace(/^\//,'').split('/'),
|
||||
newpath = '', i;
|
||||
var paths = $location.path().replace(/^\//, '').split('/'),
|
||||
newpath = '',
|
||||
i;
|
||||
idx = (Empty(idx)) ? paths.length - 1 : idx + 1;
|
||||
for (i=0; i < idx; i++) {
|
||||
for (i = 0; i < idx; i++) {
|
||||
newpath += '/' + paths[i];
|
||||
}
|
||||
$location.path(newpath);
|
||||
};
|
||||
}])
|
||||
}
|
||||
])
|
||||
|
||||
.factory('FormatDate', ['$filter', function($filter) {
|
||||
return function(dt) {
|
||||
.factory('FormatDate', ['$filter',
|
||||
function ($filter) {
|
||||
return function (dt) {
|
||||
// Wrapper for data filter- an attempt to insure all dates display in
|
||||
// the same format. Pass in date object.
|
||||
return $filter('date')(dt, 'MM/dd/yy HH:mm:ss');
|
||||
};
|
||||
}])
|
||||
}
|
||||
])
|
||||
|
||||
.factory('Wait', [ '$rootScope', function($rootScope) {
|
||||
return function(directive) {
|
||||
.factory('Wait', ['$rootScope',
|
||||
function ($rootScope) {
|
||||
return function (directive) {
|
||||
// Display a spinning icon in the center of the screen to freeze the
|
||||
// UI while waiting on async things to complete (i.e. API calls).
|
||||
// Wait('start' | 'stop');
|
||||
@ -448,16 +483,22 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
width: $(document).width(),
|
||||
height: $(document).height()
|
||||
}).fadeIn();
|
||||
$('.spinny').css({ top: y, left: x }).fadeIn(400);
|
||||
}
|
||||
else if (directive === 'stop' && $rootScope.waiting){
|
||||
$('.spinny, .overlay').fadeOut(400, function(){ $rootScope.waiting = false; });
|
||||
$('.spinny').css({
|
||||
top: y,
|
||||
left: x
|
||||
}).fadeIn(400);
|
||||
} else if (directive === 'stop' && $rootScope.waiting) {
|
||||
$('.spinny, .overlay').fadeOut(400, function () {
|
||||
$rootScope.waiting = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
}])
|
||||
|
||||
.factory('HideElement', [ function() {
|
||||
return function(selector, action) {
|
||||
}
|
||||
])
|
||||
|
||||
.factory('HideElement', [
|
||||
function () {
|
||||
return function (selector, action) {
|
||||
// Fade-in a cloack or vail or a specific element
|
||||
var target = $(selector),
|
||||
width = target.css('width'),
|
||||
@ -468,7 +509,7 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
backgroundColor = target.css('background-color'),
|
||||
margin = target.css('margin'),
|
||||
padding = target.css('padding');
|
||||
|
||||
|
||||
parent.append("<div id=\"curtain-div\" style=\"" +
|
||||
"position: absolute;" +
|
||||
"top: " + position.top + "px; " +
|
||||
@ -485,66 +526,78 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
"\"></div>");
|
||||
$('#curtain-div').show(0, action);
|
||||
};
|
||||
}])
|
||||
}
|
||||
])
|
||||
|
||||
.factory('ShowElement', [ function() {
|
||||
return function() {
|
||||
.factory('ShowElement', [
|
||||
function () {
|
||||
return function () {
|
||||
// And Fade-out the cloack revealing the element
|
||||
$('#curtain-div').fadeOut(500, function() { $(this).remove(); });
|
||||
$('#curtain-div').fadeOut(500, function () {
|
||||
$(this).remove();
|
||||
});
|
||||
};
|
||||
}])
|
||||
}
|
||||
])
|
||||
|
||||
.factory('GetChoices', [ 'Rest', 'ProcessErrors', function(Rest, ProcessErrors) {
|
||||
return function(params) {
|
||||
.factory('GetChoices', ['Rest', 'ProcessErrors',
|
||||
function (Rest, ProcessErrors) {
|
||||
return function (params) {
|
||||
// Get dropdown options
|
||||
|
||||
var scope = params.scope,
|
||||
url = params.url,
|
||||
field = params.field,
|
||||
variable = params.variable,
|
||||
callback = params.callback, // Optional. Provide if you want scop.$emit on completion.
|
||||
choice_name = params.choice_name; // Optional. Used when data is in something other than 'choices'
|
||||
callback = params.callback, // Optional. Provide if you want scop.$emit on completion.
|
||||
choice_name = params.choice_name; // Optional. Used when data is in something other than 'choices'
|
||||
|
||||
if (scope[variable]) {
|
||||
scope[variable].length = 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
scope[variable] = [];
|
||||
}
|
||||
|
||||
Rest.setUrl(url);
|
||||
Rest.options()
|
||||
.success( function(data) {
|
||||
.success(function (data) {
|
||||
var choices, i;
|
||||
choices = (choice_name) ? data.actions.GET[field][choice_name] : data.actions.GET[field].choices;
|
||||
// including 'name' property so list can be used by search
|
||||
for (i=0; i < choices.length; i++) {
|
||||
scope[variable].push({ label: choices[i][1], value: choices[i][0], name: choices[i][1]});
|
||||
for (i = 0; i < choices.length; i++) {
|
||||
scope[variable].push({
|
||||
label: choices[i][1],
|
||||
value: choices[i][0],
|
||||
name: choices[i][1]
|
||||
});
|
||||
}
|
||||
if (callback) {
|
||||
scope.$emit(callback);
|
||||
}
|
||||
})
|
||||
.error( function(data, status) {
|
||||
ProcessErrors(scope, data, status, null,
|
||||
{ hdr: 'Error!', msg: 'Failed to get ' + url + '. GET status: ' + status });
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to get ' + url + '. GET status: ' + status });
|
||||
});
|
||||
};
|
||||
}])
|
||||
|
||||
/*
|
||||
* Search an array of objects, returning the matchting object or null
|
||||
*
|
||||
* Find({ list: [], key: "key", val: <key value> });
|
||||
*/
|
||||
.factory('Find', [ function(){
|
||||
return function(params) {
|
||||
}
|
||||
])
|
||||
|
||||
/*
|
||||
* Search an array of objects, returning the matchting object or null
|
||||
*
|
||||
* Find({ list: [], key: "key", val: <key value> });
|
||||
*/
|
||||
.factory('Find', [
|
||||
function () {
|
||||
return function (params) {
|
||||
var list = params.list,
|
||||
key = params.key,
|
||||
val = params.val,
|
||||
found = false, i;
|
||||
found = false,
|
||||
i;
|
||||
if (typeof list === 'object' && Array.isArray(list)) {
|
||||
for (i=0; i < params.list.length; i++) {
|
||||
for (i = 0; i < params.list.length; i++) {
|
||||
if (list[i][key] === val) {
|
||||
found = true;
|
||||
break;
|
||||
@ -554,19 +607,22 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}])
|
||||
}
|
||||
])
|
||||
|
||||
/*
|
||||
* DeugForm({ form: <form object>, scope: <current scope object> });
|
||||
*
|
||||
* Use to log the $pristine and $valid properties of each form element. Helpful when form
|
||||
* buttons fail to enable/disable properly.
|
||||
*
|
||||
*/
|
||||
.factory('DebugForm', [ function() {
|
||||
return function(params) {
|
||||
/*
|
||||
* DeugForm({ form: <form object>, scope: <current scope object> });
|
||||
*
|
||||
* Use to log the $pristine and $valid properties of each form element. Helpful when form
|
||||
* buttons fail to enable/disable properly.
|
||||
*
|
||||
*/
|
||||
.factory('DebugForm', [
|
||||
function () {
|
||||
return function (params) {
|
||||
var form = params.form,
|
||||
scope = params.scope, fld;
|
||||
scope = params.scope,
|
||||
fld;
|
||||
for (fld in form.fields) {
|
||||
if (scope[form.name + '_form'][fld]) {
|
||||
console.log(fld + ' valid: ' + scope[form.name + '_form'][fld].$valid);
|
||||
@ -574,49 +630,52 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
if (form.fields[fld].sourceModel) {
|
||||
if (scope[form.name + '_form'][form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField]) {
|
||||
console.log(form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField + ' valid: ' +
|
||||
scope[form.name + '_form'][form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField].$valid);
|
||||
scope[form.name + '_form'][form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField].$valid);
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('form pristine: ' + scope[form.name + '_form'].$pristine);
|
||||
console.log('form valid: ' + scope[form.name + '_form'].$valid);
|
||||
};
|
||||
}])
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
/* Store
|
||||
*
|
||||
* Wrapper for local storage. All local storage requests flow through here so that we can
|
||||
* stringify/unstringify objects and respond to future issues in one place. For example,
|
||||
* we may at some point want to only use session storage rather than local storage. We might
|
||||
* want to add a test for whether or not local/session storage exists for the browser, etc.
|
||||
*
|
||||
* store(key,value) will store the value using the key
|
||||
*
|
||||
* store(key) retrieves the value of the key
|
||||
*
|
||||
*/
|
||||
.factory('Store', ['Empty', function(Empty) {
|
||||
return function(key, value) {
|
||||
|
||||
/* Store
|
||||
*
|
||||
* Wrapper for local storage. All local storage requests flow through here so that we can
|
||||
* stringify/unstringify objects and respond to future issues in one place. For example,
|
||||
* we may at some point want to only use session storage rather than local storage. We might
|
||||
* want to add a test for whether or not local/session storage exists for the browser, etc.
|
||||
*
|
||||
* store(key,value) will store the value using the key
|
||||
*
|
||||
* store(key) retrieves the value of the key
|
||||
*
|
||||
*/
|
||||
.factory('Store', ['Empty',
|
||||
function (Empty) {
|
||||
return function (key, value) {
|
||||
if (!Empty(value)) {
|
||||
// Store the value
|
||||
localStorage[key] = JSON.stringify(value);
|
||||
}
|
||||
else if (!Empty(key)) {
|
||||
} else if (!Empty(key)) {
|
||||
// Return the value
|
||||
var val = localStorage[key];
|
||||
return (!Empty(val)) ? JSON.parse(val) : null;
|
||||
}
|
||||
};
|
||||
}])
|
||||
}
|
||||
])
|
||||
|
||||
/*
|
||||
*
|
||||
* ApplyEllipsis()
|
||||
*
|
||||
*/
|
||||
.factory('ApplyEllipsis', [ function() {
|
||||
return function(selector) {
|
||||
/*
|
||||
*
|
||||
* ApplyEllipsis()
|
||||
*
|
||||
*/
|
||||
.factory('ApplyEllipsis', [
|
||||
function () {
|
||||
return function (selector) {
|
||||
// Add a hidden element to the DOM. We'll use this to calc the px length of
|
||||
// our target text.
|
||||
var tmp = $('#string-test');
|
||||
@ -625,26 +684,26 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
tmp = $('#string-test');
|
||||
}
|
||||
// Find and process the text.
|
||||
$(selector).each(function() {
|
||||
var setTitle = true, txt, w, pw, cw, df;
|
||||
$(selector).each(function () {
|
||||
var setTitle = true,
|
||||
txt, w, pw, cw, df;
|
||||
if ($(this).attr('title')) {
|
||||
txt = $(this).attr('title');
|
||||
setTitle = false;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
txt = $(this).text();
|
||||
}
|
||||
tmp.text(txt);
|
||||
w = tmp.width(); //text width
|
||||
pw = $(this).parent().width(); //parent width
|
||||
w = tmp.width(); //text width
|
||||
pw = $(this).parent().width(); //parent width
|
||||
if (w > pw) {
|
||||
// text is wider than parent width
|
||||
if (setTitle) {
|
||||
// Save the original text in the title
|
||||
$(this).attr('title',txt);
|
||||
$(this).attr('title', txt);
|
||||
}
|
||||
cw = w / txt.length; // px width per character
|
||||
df = w - pw; // difference in px
|
||||
df = w - pw; // difference in px
|
||||
txt = txt.substr(0, txt.length - (Math.ceil(df / cw) + 3));
|
||||
$(this).text(txt + '...');
|
||||
}
|
||||
@ -654,16 +713,7 @@ angular.module('Utilities',['RestServices', 'Utilities'])
|
||||
$(this).text(txt);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
}]);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
]);
|
||||
@ -1,45 +1,53 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Read /api and /api/X to discover all the base paths needed
|
||||
* to access the primary model objects.
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('ApiLoader', ['Utilities'])
|
||||
|
||||
.factory('LoadBasePaths', ['$http', '$rootScope', 'Store', 'ProcessErrors',
|
||||
function($http, $rootScope, Store, ProcessErrors) {
|
||||
return function() {
|
||||
.factory('LoadBasePaths', ['$http', '$rootScope', 'Store', 'ProcessErrors',
|
||||
function ($http, $rootScope, Store, ProcessErrors) {
|
||||
return function () {
|
||||
$http.get('/api/')
|
||||
.success( function(data) {
|
||||
.success(function (data) {
|
||||
var base = data.current_version;
|
||||
$http.get(base)
|
||||
.success( function(data) {
|
||||
.success(function (data) {
|
||||
data.base = base;
|
||||
$rootScope.defaultUrls = data;
|
||||
Store('api', data);
|
||||
})
|
||||
.error ( function(data, status) {
|
||||
$rootScope.defaultUrls = { status: 'error' };
|
||||
ProcessErrors(null, data, status, null,
|
||||
{ hdr: 'Error', msg: 'Failed to read ' + base + '. GET status: ' + status });
|
||||
.error(function (data, status) {
|
||||
$rootScope.defaultUrls = {
|
||||
status: 'error'
|
||||
};
|
||||
ProcessErrors(null, data, status, null, {
|
||||
hdr: 'Error',
|
||||
msg: 'Failed to read ' + base + '. GET status: ' + status
|
||||
});
|
||||
});
|
||||
})
|
||||
.error( function(data, status) {
|
||||
$rootScope.defaultUrls = { status: 'error' };
|
||||
ProcessErrors(null, data, status, null,
|
||||
{ hdr: 'Error', msg: 'Failed to read /api. GET status: ' + status });
|
||||
.error(function (data, status) {
|
||||
$rootScope.defaultUrls = {
|
||||
status: 'error'
|
||||
};
|
||||
ProcessErrors(null, data, status, null, {
|
||||
hdr: 'Error',
|
||||
msg: 'Failed to read /api. GET status: ' + status
|
||||
});
|
||||
});
|
||||
};
|
||||
}])
|
||||
}
|
||||
])
|
||||
|
||||
.factory('GetBasePath', ['$rootScope', 'Store', 'LoadBasePaths', 'Empty',
|
||||
function($rootScope, Store, LoadBasePaths, Empty) {
|
||||
return function(set) {
|
||||
.factory('GetBasePath', ['$rootScope', 'Store', 'LoadBasePaths', 'Empty',
|
||||
function ($rootScope, Store, LoadBasePaths, Empty) {
|
||||
return function (set) {
|
||||
// use /api/v1/ results to construct API URLs.
|
||||
if (Empty($rootScope.defaultUrls)) {
|
||||
// browser refresh must have occurred. load from local storage
|
||||
@ -47,11 +55,9 @@ angular.module('ApiLoader', ['Utilities'])
|
||||
$rootScope.defaultUrls = Store('api');
|
||||
return $rootScope.defaultUrls[set];
|
||||
}
|
||||
return ''; //we should never get here
|
||||
return ''; //we should never get here
|
||||
}
|
||||
return $rootScope.defaultUrls[set];
|
||||
};
|
||||
}]);
|
||||
|
||||
|
||||
|
||||
}
|
||||
]);
|
||||
@ -10,6 +10,7 @@
|
||||
/* global chkPass:false */
|
||||
|
||||
angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'JobsHelper'])
|
||||
|
||||
// awpassmatch: Add to password_confirm field. Will test if value
|
||||
// matches that of 'input[name="password"]'
|
||||
.directive('awpassmatch', function() {
|
||||
|
||||
@ -1,26 +1,29 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* Custom filters
|
||||
* Custom filters
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('AWFilters', [])
|
||||
|
||||
//
|
||||
// capitalize -capitalize the first letter of each word
|
||||
//
|
||||
.filter('capitalize', [ function() {
|
||||
return function(input) {
|
||||
var values, result, i;
|
||||
if (input) {
|
||||
values = input.replace(/\_/g,' ').split(" ");
|
||||
result = "";
|
||||
for (i = 0; i < values.length; i++){
|
||||
result += values[i].charAt(0).toUpperCase() + values[i].substr(1) + ' ';
|
||||
.filter('capitalize', [
|
||||
function () {
|
||||
return function (input) {
|
||||
var values, result, i;
|
||||
if (input) {
|
||||
values = input.replace(/\_/g, ' ').split(" ");
|
||||
result = "";
|
||||
for (i = 0; i < values.length; i++) {
|
||||
result += values[i].charAt(0).toUpperCase() + values[i].substr(1) + ' ';
|
||||
}
|
||||
return result.trim();
|
||||
}
|
||||
return result.trim();
|
||||
}
|
||||
};
|
||||
}]);
|
||||
};
|
||||
}
|
||||
]);
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -9,200 +9,129 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('License', ['RestServices', 'Utilities', 'FormGenerator', 'PromptDialog'])
|
||||
.factory('ViewLicense', ['$location', '$rootScope', 'GenerateForm', 'Rest', 'Alert', 'GetBasePath', 'ProcessErrors',
|
||||
'FormatDate', 'Prompt', 'Empty',
|
||||
function($location, $rootScope, GenerateForm, Rest, Alert, GetBasePath, ProcessErrors, FormatDate, Prompt, Empty) {
|
||||
return function() {
|
||||
|
||||
var defaultUrl=GetBasePath('config');
|
||||
var generator = GenerateForm;
|
||||
|
||||
var form = {
|
||||
name: 'license',
|
||||
well: false,
|
||||
forceListeners: true,
|
||||
fields: {
|
||||
license_status: {
|
||||
type: 'custom',
|
||||
control: '<div class=\"license-status\" ng-class=\"status_color\"><i class="fa fa-circle"></i> \{\{ license_status \}\}</span></div>',
|
||||
readonly: true,
|
||||
section: 'License'
|
||||
},
|
||||
license_key: {
|
||||
label: 'Key',
|
||||
type: 'textarea',
|
||||
'class': 'modal-input-xlarge',
|
||||
readonly: true,
|
||||
section: 'License'
|
||||
},
|
||||
license_date: {
|
||||
label: 'Expires On',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'License'
|
||||
},
|
||||
time_remaining: {
|
||||
label: 'Time Left',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'License'
|
||||
},
|
||||
available_instances: {
|
||||
label: 'Available',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Managed Hosts'
|
||||
},
|
||||
current_instances: {
|
||||
label: 'Used',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Managed Hosts'
|
||||
},
|
||||
free_instances: {
|
||||
label: 'Remaining',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Managed Hosts',
|
||||
controlNGClass: 'free_instances_class',
|
||||
labelNGClass: 'free_instances_class'
|
||||
},
|
||||
company_name: {
|
||||
label: 'Company',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Contact Info'
|
||||
},
|
||||
contact_name: {
|
||||
label: 'Contact',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Contact Info'
|
||||
},
|
||||
contact_email: {
|
||||
label: 'Contact Email',
|
||||
type: 'text',
|
||||
readonly: true,
|
||||
section: 'Contact Info'
|
||||
}
|
||||
}
|
||||
};
|
||||
angular.module('License', ['RestServices', 'Utilities', 'FormGenerator', 'PromptDialog', 'LicenseFormDefinition'])
|
||||
.factory('ViewLicense', ['$location', '$rootScope', 'GenerateForm', 'Rest', 'Alert', 'GetBasePath', 'ProcessErrors',
|
||||
'FormatDate', 'Prompt', 'Empty', 'LicenseForm',
|
||||
function ($location, $rootScope, GenerateForm, Rest, Alert, GetBasePath, ProcessErrors, FormatDate, Prompt, Empty,
|
||||
LicenseForm) {
|
||||
return function () {
|
||||
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
|
||||
|
||||
// Retrieve detail record and prepopulate the form
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.get()
|
||||
.success( function(data, status, headers, config) {
|
||||
|
||||
for (var fld in form.fields) {
|
||||
if (fld != 'time_remaining' && fld != 'license_status') {
|
||||
if (Empty(data['license_info'][fld])) {
|
||||
delete form.fields[fld];
|
||||
}
|
||||
}
|
||||
}
|
||||
var defaultUrl = GetBasePath('config'),
|
||||
generator = GenerateForm,
|
||||
form = angular.copy(LicenseForm),
|
||||
scope;
|
||||
|
||||
if (data['license_info']['is_aws'] || Empty(data['license_info']['license_date'])) {
|
||||
delete form.fields['license_date'];
|
||||
delete form.fields['time_remaining'];
|
||||
}
|
||||
// Retrieve detail record and prepopulate the form
|
||||
Rest.setUrl(defaultUrl);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
|
||||
var scope = generator.inject(form, { mode: 'edit', modal: true, related: false});
|
||||
generator.reset();
|
||||
|
||||
scope.formModalAction = function() {
|
||||
$('#form-modal').modal("hide");
|
||||
}
|
||||
|
||||
scope.formModalActionLabel = 'OK';
|
||||
scope.formModalCancelShow = false;
|
||||
scope.formModalInfo = 'Purchase/Extend License';
|
||||
scope.formModalHeader = 'Tower License';
|
||||
var fld, dt, days, remainder, hours, minutes, seconds, license;
|
||||
|
||||
for (fld in form.fields) {
|
||||
if (fld !== 'time_remaining' && fld !== 'license_status') {
|
||||
if (Empty(data.license_info[fld])) {
|
||||
delete form.fields[fld];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//$('#form-modal .btn-success').removeClass('btn-success').addClass('btn-none');
|
||||
//$('#form-modal').addClass('skinny-modal');
|
||||
|
||||
|
||||
// Respond to license button
|
||||
scope.formModalInfoAction = function() {
|
||||
Prompt({
|
||||
hdr: 'Tower Licensing',
|
||||
body: "<p>Ansible Tower licenses can be purchased or extended by visiting <a id=\"license-link\" " +
|
||||
"href=\"http://www.ansible.com/ansible-pricing\" target=\"_blank\">" +
|
||||
"the Ansible online store</a>. Would you like to purchase or extend your license now?</p>",
|
||||
'class': 'btn-primary',
|
||||
action: function() {
|
||||
var href = $('#license-link').attr('href');
|
||||
window.open(href, 'storeWindow');
|
||||
}
|
||||
});
|
||||
}
|
||||
if (data.license_info.is_aws || Empty(data.license_info.license_date)) {
|
||||
delete form.fields.license_date;
|
||||
delete form.fields.time_remaining;
|
||||
}
|
||||
|
||||
for (var fld in form.fields) {
|
||||
if (!Empty(data['license_info'][fld])) {
|
||||
scope[fld] = data['license_info'][fld];
|
||||
}
|
||||
}
|
||||
|
||||
if (scope['license_date']) {
|
||||
var dt = new Date(parseInt(scope['license_date']));
|
||||
if (dt.getFullYear() == '1970') {
|
||||
// date was passed in seconds rather than milliseconds
|
||||
dt = new Date(parseInt(scope['license_date']) * 1000);
|
||||
scope['time_remaining'] = scope['time_remaining'] + '000';
|
||||
}
|
||||
scope['license_date'] = FormatDate(dt);
|
||||
scope = generator.inject(form, { mode: 'edit', modal: true, related: false });
|
||||
generator.reset();
|
||||
|
||||
var days = parseInt(scope['time_remaining'] / 86400000);
|
||||
var remainder = scope['time_remaining'] - (days * 86400000);
|
||||
var hours = parseInt(remainder / 3600000);
|
||||
remainder = remainder - (hours * 3600000);
|
||||
var minutes = parseInt(remainder / 60000);
|
||||
remainder = remainder - (minutes * 60000);
|
||||
var seconds = parseInt(remainder / 1000);
|
||||
scope['time_remaining'] = days + ' days ' + ('0' + hours).slice(-2) + ':' + ('0' + minutes).slice(-2) + ':' + ('0' + seconds).slice(-2);
|
||||
}
|
||||
scope.formModalAction = function () {
|
||||
$('#form-modal').modal("hide");
|
||||
};
|
||||
|
||||
if (parseInt(scope['free_instances']) <= 0) {
|
||||
scope['free_instances_class'] = 'field-failure';
|
||||
}
|
||||
else {
|
||||
scope['free_instances_class'] = 'field-success';
|
||||
}
|
||||
scope.formModalActionLabel = 'OK';
|
||||
scope.formModalCancelShow = false;
|
||||
scope.formModalInfo = 'Purchase/Extend License';
|
||||
scope.formModalHeader = 'Tower License';
|
||||
|
||||
var license = data['license_info'];
|
||||
if (license['valid_key'] !== undefined && license['valid_key'] == false) {
|
||||
scope['license_status'] = 'Invalid';
|
||||
scope['status_color'] = 'license-invalid';
|
||||
}
|
||||
else if (license['demo'] !== undefined && license['demo'] == true) {
|
||||
scope['license_status'] = 'Demo';
|
||||
scope['status_color'] = 'license-demo';
|
||||
}
|
||||
else if (license['date_expired'] !== undefined && license['date_expired'] == true) {
|
||||
scope['license_status'] = 'Expired';
|
||||
scope['status_color'] = 'license-expired';
|
||||
}
|
||||
else if (license['date_warning'] !== undefined && license['date_warning'] == true) {
|
||||
scope['license_status'] = 'Expiration Warning';
|
||||
scope['status_color'] = 'license-warning';
|
||||
}
|
||||
else if (license['free_instances'] !== undefined && parseInt(license['free_instances']) <= 0) {
|
||||
scope['license_status'] = 'No available managed hosts';
|
||||
scope['status_color'] = 'license-invalid';
|
||||
}
|
||||
else {
|
||||
scope['license_status'] = 'Valid';
|
||||
scope['status_color'] = 'license-valid';
|
||||
}
|
||||
//$('#form-modal .btn-success').removeClass('btn-success').addClass('btn-none');
|
||||
//$('#form-modal').addClass('skinny-modal');
|
||||
|
||||
})
|
||||
.error( function(data, status, headers, config) {
|
||||
ProcessErrors($rootScope, data, status, form,
|
||||
{ hdr: 'Error!', msg: 'Failed to retrieve license. GET status: ' + status });
|
||||
});
|
||||
}
|
||||
}]);
|
||||
|
||||
// Respond to license button
|
||||
scope.formModalInfoAction = function () {
|
||||
Prompt({
|
||||
hdr: 'Tower Licensing',
|
||||
body: "<p>Ansible Tower licenses can be purchased or extended by visiting <a id=\"license-link\" " +
|
||||
"href=\"http://www.ansible.com/ansible-pricing\" target=\"_blank\">" +
|
||||
"the Ansible online store</a>. Would you like to purchase or extend your license now?</p>",
|
||||
'class': 'btn-primary',
|
||||
action: function () {
|
||||
var href = $('#license-link').attr('href');
|
||||
window.open(href, 'storeWindow');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
for (fld in form.fields) {
|
||||
if (!Empty(data.license_info[fld])) {
|
||||
scope[fld] = data.license_info[fld];
|
||||
}
|
||||
}
|
||||
|
||||
if (scope.license_date) {
|
||||
dt = new Date(parseInt(scope.license_date));
|
||||
if (dt.getFullYear() === '1970') {
|
||||
// date was passed in seconds rather than milliseconds
|
||||
dt = new Date(parseInt(scope.license_date,10) * 1000);
|
||||
scope.time_remaining = scope.time_remaining + '000';
|
||||
}
|
||||
scope.license_date = FormatDate(dt);
|
||||
|
||||
days = parseInt(scope.time_remaining / 86400000, 10);
|
||||
remainder = scope.time_remaining - (days * 86400000);
|
||||
hours = parseInt(remainder / 3600000, 10);
|
||||
remainder = remainder - (hours * 3600000);
|
||||
minutes = parseInt(remainder / 60000, 10);
|
||||
remainder = remainder - (minutes * 60000);
|
||||
seconds = parseInt(remainder / 1000, 10);
|
||||
scope.time_remaining = days + ' days ' + ('0' + hours).slice(-2) + ':' + ('0' + minutes).slice(-2) + ':' +
|
||||
('0' + seconds).slice(-2);
|
||||
}
|
||||
|
||||
if (parseInt(scope.free_instances) <= 0) {
|
||||
scope.free_instances_class = 'field-failure';
|
||||
} else {
|
||||
scope.free_instances_class = 'field-success';
|
||||
}
|
||||
|
||||
license = data.license_info;
|
||||
if (license.valid_key !== undefined && !license.valid_key) {
|
||||
scope.license_status = 'Invalid';
|
||||
scope.status_color = 'license-invalid';
|
||||
} else if (license.demo !== undefined && license.demo) {
|
||||
scope.license_status = 'Demo';
|
||||
scope.status_color = 'license-demo';
|
||||
} else if (license.date_expired !== undefined && license.date_expired) {
|
||||
scope.license_status = 'Expired';
|
||||
scope.status_color = 'license-expired';
|
||||
} else if (license.date_warning !== undefined && license.date_warning) {
|
||||
scope.license_status = 'Expiration Warning';
|
||||
scope.status_color = 'license-warning';
|
||||
} else if (license.free_instances !== undefined && parseInt(license.free_instances) <= 0) {
|
||||
scope.license_status = 'No available managed hosts';
|
||||
scope.status_color = 'license-invalid';
|
||||
} else {
|
||||
scope.license_status = 'Valid';
|
||||
scope.status_color = 'license-valid';
|
||||
}
|
||||
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($rootScope, data, status, form, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to retrieve license. GET status: ' + status
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -1,7 +1,7 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* ListGenerator
|
||||
* ListGenerator
|
||||
* Pass in a list definition from ListDefinitions and out pops an html template.
|
||||
* Use inject method to generate the html and inject into the current view.
|
||||
*
|
||||
@ -10,412 +10,439 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('ListGenerator', ['GeneratorHelpers'])
|
||||
.factory('GenerateList', [ '$location', '$compile', '$rootScope', 'SearchWidget', 'PaginateWidget', 'Attr', 'Icon',
|
||||
.factory('GenerateList', ['$location', '$compile', '$rootScope', 'SearchWidget', 'PaginateWidget', 'Attr', 'Icon',
|
||||
'Column', 'DropDown', 'NavigationLink', 'Button', 'SelectIcon', 'Breadcrumbs',
|
||||
function($location, $compile, $rootScope, SearchWidget, PaginateWidget, Attr, Icon, Column, DropDown, NavigationLink, Button, SelectIcon,
|
||||
Breadcrumbs) {
|
||||
return {
|
||||
|
||||
setList: function(list) {
|
||||
this.list = list;
|
||||
},
|
||||
|
||||
attr: Attr,
|
||||
function ($location, $compile, $rootScope, SearchWidget, PaginateWidget, Attr, Icon, Column, DropDown, NavigationLink, Button, SelectIcon,
|
||||
Breadcrumbs) {
|
||||
return {
|
||||
|
||||
icon: Icon,
|
||||
setList: function (list) {
|
||||
this.list = list;
|
||||
},
|
||||
|
||||
has: function(key) {
|
||||
return (this.form[key] && this.form[key] !== null && this.form[key] !== undefined) ? true : false;
|
||||
},
|
||||
attr: Attr,
|
||||
|
||||
hide: function() {
|
||||
$('#lookup-modal').modal('hide');
|
||||
},
|
||||
icon: Icon,
|
||||
|
||||
button: Button,
|
||||
has: function (key) {
|
||||
return (this.form[key] && this.form[key] !== null && this.form[key] !== undefined) ? true : false;
|
||||
},
|
||||
|
||||
inject: function(list, options) {
|
||||
// options.mode = one of edit, select or lookup
|
||||
//
|
||||
// Modes edit and select will inject the list as html into element #htmlTemplate.
|
||||
// 'lookup' mode injects the list html into #lookup-modal-body.
|
||||
//
|
||||
// For options.mode == 'lookup', include the following:
|
||||
//
|
||||
// hdr: <lookup dialog header>
|
||||
//
|
||||
// Inject into a custom element using options.id: <'.selector'>
|
||||
// Control breadcrumb creation with options.breadCrumbs: <true | false>
|
||||
//
|
||||
var element;
|
||||
hide: function () {
|
||||
$('#lookup-modal').modal('hide');
|
||||
},
|
||||
|
||||
if (options.mode === 'lookup') {
|
||||
element = angular.element(document.getElementById('lookup-modal-body'));
|
||||
}
|
||||
else if (options.id) {
|
||||
element = angular.element(document.getElementById(options.id));
|
||||
}
|
||||
else {
|
||||
element = angular.element(document.getElementById('htmlTemplate'));
|
||||
}
|
||||
this.setList(list);
|
||||
element.html(this.build(options)); // Inject the html
|
||||
if (options.prepend) { // Add any extra HTML passed in options
|
||||
element.prepend(options.prepend);
|
||||
}
|
||||
if (options.append) {
|
||||
element.append(options.prepend);
|
||||
}
|
||||
|
||||
if (options.scope) {
|
||||
this.scope = options.scope;
|
||||
}
|
||||
else {
|
||||
this.scope = element.scope(); // Set scope specific to the element we're compiling, avoids circular reference
|
||||
} // From here use 'scope' to manipulate the form, as the form is not in '$scope'
|
||||
|
||||
$compile(element)(this.scope);
|
||||
button: Button,
|
||||
|
||||
// Reset the scope to prevent displaying old data from our last visit to this list
|
||||
this.scope[list.name] = null;
|
||||
this.scope[list.iterator] = null;
|
||||
inject: function (list, options) {
|
||||
// options.mode = one of edit, select or lookup
|
||||
//
|
||||
// Modes edit and select will inject the list as html into element #htmlTemplate.
|
||||
// 'lookup' mode injects the list html into #lookup-modal-body.
|
||||
//
|
||||
// For options.mode == 'lookup', include the following:
|
||||
//
|
||||
// hdr: <lookup dialog header>
|
||||
//
|
||||
// Inject into a custom element using options.id: <'.selector'>
|
||||
// Control breadcrumb creation with options.breadCrumbs: <true | false>
|
||||
//
|
||||
var element;
|
||||
|
||||
// Remove any lingering tooltip and popover <div> elements
|
||||
$('.tooltip').each( function(index) {
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
$('.popover').each(function(index) {
|
||||
// remove lingering popover <div>. Seems to be a bug in TB3 RC1
|
||||
$(this).remove();
|
||||
});
|
||||
$(window).unbind('resize');
|
||||
|
||||
try {
|
||||
$('#help-modal').empty().dialog('destroy');
|
||||
}
|
||||
catch(e) {
|
||||
//ignore any errors should the dialog not be initialized
|
||||
}
|
||||
|
||||
if (options.mode === 'lookup') {
|
||||
// options should include {hdr: <dialog header>, action: <function...> }
|
||||
this.scope.formModalActionDisabled = false;
|
||||
this.scope.lookupHeader = options.hdr;
|
||||
$('#lookup-modal').modal({ backdrop: 'static', keyboard: true });
|
||||
$('#lookup-modal').unbind('hidden.bs.modal');
|
||||
$(document).bind('keydown', function(e) {
|
||||
if (e.keyCode === 27) {
|
||||
$('#lookup-modal').modal('hide');
|
||||
if (options.mode === 'lookup') {
|
||||
element = angular.element(document.getElementById('lookup-modal-body'));
|
||||
} else if (options.id) {
|
||||
element = angular.element(document.getElementById(options.id));
|
||||
} else {
|
||||
element = angular.element(document.getElementById('htmlTemplate'));
|
||||
}
|
||||
this.setList(list);
|
||||
element.html(this.build(options)); // Inject the html
|
||||
if (options.prepend) { // Add any extra HTML passed in options
|
||||
element.prepend(options.prepend);
|
||||
}
|
||||
if (options.append) {
|
||||
element.append(options.prepend);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return this.scope;
|
||||
},
|
||||
|
||||
build: function(options) {
|
||||
//
|
||||
// Generate HTML. Do NOT call this function directly. Called by inject(). Returns an HTML
|
||||
// string to be injected into the current view.
|
||||
//
|
||||
var html = '';
|
||||
var list = this.list;
|
||||
if (options.scope) {
|
||||
this.scope = options.scope;
|
||||
} else {
|
||||
this.scope = element.scope(); // Set scope specific to the element we're compiling, avoids circular reference
|
||||
} // From here use 'scope' to manipulate the form, as the form is not in '$scope'
|
||||
|
||||
if (options.activityStream) {
|
||||
// Breadcrumbs for activity stream widget
|
||||
// Make the links clickable using ng-click function so we can first remove the stream widget
|
||||
// before navigation
|
||||
html += "<div class=\"nav-path\">\n";
|
||||
html += "<ul class=\"breadcrumb\">\n";
|
||||
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"\" ng-click=\"\{\{ crumb.ngClick \}\}\">{{ crumb.title }}</a></li>\n";
|
||||
html += "<li class=\"active\">";
|
||||
html += list.editTitle;
|
||||
html += "</li>\n</ul>\n</div>\n";
|
||||
}
|
||||
else if (options.mode != 'lookup' && (options.breadCrumbs == undefined || options.breadCrumbs == true)) {
|
||||
//Breadcrumbs
|
||||
html += Breadcrumbs({ list: list, mode: options.mode });
|
||||
}
|
||||
|
||||
if (options.mode == 'edit' && list.editInstructions) {
|
||||
html += "<div class=\"alert alert-info alert-block\">\n";
|
||||
html += "<button type=\"button\" class=\"close\" data-dismiss=\"alert\">×</button>\n";
|
||||
html += "<strong>Hint: </strong>" + list.editInstructions + "\n";
|
||||
html += "</div>\n";
|
||||
}
|
||||
|
||||
if (options.mode != 'lookup' && (list.well == undefined || list.well == true)) {
|
||||
html += "<div class=\"well\">\n";
|
||||
}
|
||||
|
||||
if (options.activityStream) {
|
||||
// Add a title row
|
||||
html += "<div class=\"row\">\n";
|
||||
html += "<div class=\"col-lg-12\">\n";
|
||||
html += "<h5>{{ streamTitle }}</h5>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
}
|
||||
$compile(element)(this.scope);
|
||||
|
||||
html += "<div class=\"row\">\n";
|
||||
|
||||
if (list.name != 'groups') {
|
||||
if (options.searchSize) {
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: options.searchSize,
|
||||
searchWidgets: list.searchWidgets });
|
||||
}
|
||||
else if (options.mode == 'summary') {
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-6' });
|
||||
}
|
||||
else if (options.mode == 'lookup' || options.id != undefined) {
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true , size: 'col-lg-8' });
|
||||
}
|
||||
else {
|
||||
html += SearchWidget({ iterator: list.iterator, template: list, mini: true });
|
||||
}
|
||||
}
|
||||
// Reset the scope to prevent displaying old data from our last visit to this list
|
||||
this.scope[list.name] = null;
|
||||
this.scope[list.iterator] = null;
|
||||
|
||||
if (options.mode != 'lookup') {
|
||||
//actions
|
||||
var base = $location.path().replace(/^\//,'').split('/')[0];
|
||||
html += "<div class=\"";
|
||||
if (list.name == 'groups') {
|
||||
html += "col-lg-12";
|
||||
}
|
||||
else if (options.searchSize) {
|
||||
// User supplied searchSize, calc the remaining
|
||||
var size = parseInt(options.searchSize.replace(/([A-Z]|[a-z]|\-)/g,''));
|
||||
size = (list.searchWidgets) ? list.searchWidgets * size : size;
|
||||
html += 'col-lg-' + (12 - size);
|
||||
}
|
||||
else if (options.mode == 'summary') {
|
||||
html += 'col-lg-6';
|
||||
}
|
||||
else if (options.id != undefined) {
|
||||
html += "col-lg-4";
|
||||
}
|
||||
else {
|
||||
html += "col-lg-8 col-md-6";
|
||||
}
|
||||
html += "\">\n";
|
||||
|
||||
html += "<div class=\"list-actions\">\n";
|
||||
|
||||
// Add toolbar buttons or 'actions'
|
||||
for (var action in list.actions) {
|
||||
if (list.actions[action].mode == 'all' || list.actions[action].mode == options.mode) {
|
||||
if ( (list.actions[action].basePaths == undefined) ||
|
||||
(list.actions[action].basePaths && list.actions[action].basePaths.indexOf(base) > -1) ) {
|
||||
html += this.button({ btn: list.actions[action], action: action, toolbar: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove any lingering tooltip and popover <div> elements
|
||||
$('.tooltip').each(function() {
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
//select instructions
|
||||
if (options.mode == 'select' && list.selectInstructions) {
|
||||
var btn = {
|
||||
awPopOver: list.selectInstructions,
|
||||
dataPlacement: 'top',
|
||||
dataContainer: 'body',
|
||||
'class': 'btn-xs btn-help',
|
||||
awToolTip: 'Click for help',
|
||||
dataTitle: 'Help',
|
||||
iconSize: 'fa-lg'
|
||||
};
|
||||
//html += this.button(btn, 'select');
|
||||
html += this.button({ btn: btn, action: 'help', toolbar: true });
|
||||
}
|
||||
$('.popover').each(function() {
|
||||
// remove lingering popover <div>. Seems to be a bug in TB3 RC1
|
||||
$(this).remove();
|
||||
});
|
||||
$(window).unbind('resize');
|
||||
|
||||
html += "</div><!-- list-acitons -->\n";
|
||||
html += "</div><!-- list-actions-column -->\n";
|
||||
}
|
||||
else {
|
||||
//lookup
|
||||
html += "<div class=\"col-lg-7\"></div>\n";
|
||||
}
|
||||
try {
|
||||
$('#help-modal').empty().dialog('destroy');
|
||||
} catch (e) {
|
||||
//ignore any errors should the dialog not be initialized
|
||||
}
|
||||
|
||||
html += "</div><!-- row -->\n";
|
||||
|
||||
// Add a title and optionally a close button (used on Inventory->Groups)
|
||||
if (options.mode !== 'lookup' && list.showTitle) {
|
||||
html += "<div class=\"form-title\">";
|
||||
html += (options.mode == 'edit' || options.mode == 'summary') ? list.editTitle : list.addTitle;
|
||||
html += "</div>\n";
|
||||
}
|
||||
if (options.mode === 'lookup') {
|
||||
// options should include {hdr: <dialog header>, action: <function...> }
|
||||
this.scope.formModalActionDisabled = false;
|
||||
this.scope.lookupHeader = options.hdr;
|
||||
$('#lookup-modal').modal({
|
||||
backdrop: 'static',
|
||||
keyboard: true
|
||||
});
|
||||
$('#lookup-modal').unbind('hidden.bs.modal');
|
||||
$(document).bind('keydown', function (e) {
|
||||
if (e.keyCode === 27) {
|
||||
$('#lookup-modal').modal('hide');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// table header row
|
||||
html += "<table id=\"" + list.name + "_table\" ";
|
||||
html += "class=\"table"
|
||||
html += (list['class']) ? " " + list['class'] : "";
|
||||
html += (options.mode !== 'summary' && options.mode !== 'edit' && (options.mode == 'lookup' || options.id)) ?
|
||||
' table-hover-inverse' : '';
|
||||
html += (list.hover) ? ' table-hover' : '';
|
||||
html += (options.mode == 'summary') ? ' table-summary' : '';
|
||||
html += "\" ";
|
||||
html += ">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>\n";
|
||||
if (list.index) {
|
||||
html += "<th class=\"col-lg-1 col-md-1 col-sm-1 hidden-xs\">#</th>\n";
|
||||
}
|
||||
for (var fld in list.fields) {
|
||||
if ( (list.fields[fld].searchOnly == undefined || list.fields[fld].searchOnly == false) &&
|
||||
!(options.mode == 'lookup' && list.fields[fld].excludeModal !== undefined && list.fields[fld].excludeModal == true) ) {
|
||||
html += "<th class=\"list-header";
|
||||
html += (list.fields[fld].columnClass) ? " " + list.fields[fld].columnClass : "";
|
||||
html += "\" id=\"";
|
||||
html += (list.fields[fld].id) ? list.fields[fld].id : fld + "-header";
|
||||
html += "\"";
|
||||
html += (list.fields[fld].columnShow) ? " ng-show=\"" + list.fields[fld].columnShow + "\" " : "";
|
||||
html += (list.fields[fld].nosort === undefined || list.fields[fld].nosort !== true) ? "ng-click=\"sort('" + fld + "')\"" : "";
|
||||
html += ">";
|
||||
html += list.fields[fld].label;
|
||||
if (list.fields[fld].nosort === undefined || list.fields[fld].nosort !== true) {
|
||||
html += " <i class=\"fa ";
|
||||
if (list.fields[fld].key) {
|
||||
if (list.fields[fld].desc) {
|
||||
html += "fa-sort-down";
|
||||
}
|
||||
else {
|
||||
html += "fa-sort-up";
|
||||
return this.scope;
|
||||
},
|
||||
|
||||
build: function (options) {
|
||||
//
|
||||
// Generate HTML. Do NOT call this function directly. Called by inject(). Returns an HTML
|
||||
// string to be injected into the current view.
|
||||
//
|
||||
var html = '',
|
||||
list = this.list,
|
||||
base, size, action, btn, fld, cnt, field_action, fAction, itm;
|
||||
|
||||
if (options.activityStream) {
|
||||
// Breadcrumbs for activity stream widget
|
||||
// Make the links clickable using ng-click function so we can first remove the stream widget
|
||||
// before navigation
|
||||
html += "<div class=\"nav-path\">\n";
|
||||
html += "<ul class=\"breadcrumb\">\n";
|
||||
html += "<li ng-repeat=\"crumb in breadcrumbs\"><a href=\"\" " +
|
||||
"ng-click=\"{{ crumb.ngClick }}\">{{ crumb.title }}</a></li>\n";
|
||||
html += "<li class=\"active\">";
|
||||
html += list.editTitle;
|
||||
html += "</li>\n</ul>\n</div>\n";
|
||||
} else if (options.mode !== 'lookup' && (options.breadCrumbs === undefined || options.breadCrumbs)) {
|
||||
//Breadcrumbs
|
||||
html += Breadcrumbs({
|
||||
list: list,
|
||||
mode: options.mode
|
||||
});
|
||||
}
|
||||
|
||||
if (options.mode === 'edit' && list.editInstructions) {
|
||||
html += "<div class=\"alert alert-info alert-block\">\n";
|
||||
html += "<button type=\"button\" class=\"close\" data-dismiss=\"alert\">×</button>\n";
|
||||
html += "<strong>Hint: </strong>" + list.editInstructions + "\n";
|
||||
html += "</div>\n";
|
||||
}
|
||||
|
||||
if (options.mode !== 'lookup' && (list.well === undefined || list.well)) {
|
||||
html += "<div class=\"well\">\n";
|
||||
}
|
||||
|
||||
if (options.activityStream) {
|
||||
// Add a title row
|
||||
html += "<div class=\"row\">\n";
|
||||
html += "<div class=\"col-lg-12\">\n";
|
||||
html += "<h5>{{ streamTitle }}</h5>\n";
|
||||
html += "</div>\n";
|
||||
html += "</div>\n";
|
||||
}
|
||||
|
||||
html += "<div class=\"row\">\n";
|
||||
|
||||
if (list.name !== 'groups') {
|
||||
if (options.searchSize) {
|
||||
html += SearchWidget({
|
||||
iterator: list.iterator,
|
||||
template: list,
|
||||
mini: true,
|
||||
size: options.searchSize,
|
||||
searchWidgets: list.searchWidgets
|
||||
});
|
||||
} else if (options.mode === 'summary') {
|
||||
html += SearchWidget({
|
||||
iterator: list.iterator,
|
||||
template: list,
|
||||
mini: true,
|
||||
size: 'col-lg-6'
|
||||
});
|
||||
} else if (options.mode === 'lookup' || options.id !== undefined) {
|
||||
html += SearchWidget({
|
||||
iterator: list.iterator,
|
||||
template: list,
|
||||
mini: true,
|
||||
size: 'col-lg-8'
|
||||
});
|
||||
} else {
|
||||
html += SearchWidget({
|
||||
iterator: list.iterator,
|
||||
template: list,
|
||||
mini: true
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
html += "fa-sort";
|
||||
}
|
||||
html += "\"></i></a>";
|
||||
|
||||
if (options.mode !== 'lookup') {
|
||||
//actions
|
||||
base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
html += "<div class=\"";
|
||||
if (list.name === 'groups') {
|
||||
html += "col-lg-12";
|
||||
} else if (options.searchSize) {
|
||||
// User supplied searchSize, calc the remaining
|
||||
size = parseInt(options.searchSize.replace(/([A-Z]|[a-z]|\-)/g, ''));
|
||||
size = (list.searchWidgets) ? list.searchWidgets * size : size;
|
||||
html += 'col-lg-' + (12 - size);
|
||||
} else if (options.mode === 'summary') {
|
||||
html += 'col-lg-6';
|
||||
} else if (options.id !== undefined) {
|
||||
html += "col-lg-4";
|
||||
} else {
|
||||
html += "col-lg-8 col-md-6";
|
||||
}
|
||||
html += "\">\n";
|
||||
|
||||
html += "<div class=\"list-actions\">\n";
|
||||
|
||||
// Add toolbar buttons or 'actions'
|
||||
for (action in list.actions) {
|
||||
if (list.actions[action].mode === 'all' || list.actions[action].mode === options.mode) {
|
||||
if ((list.actions[action].basePaths === undefined) ||
|
||||
(list.actions[action].basePaths && list.actions[action].basePaths.indexOf(base) > -1)) {
|
||||
html += this.button({
|
||||
btn: list.actions[action],
|
||||
action: action,
|
||||
toolbar: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//select instructions
|
||||
if (options.mode === 'select' && list.selectInstructions) {
|
||||
btn = {
|
||||
awPopOver: list.selectInstructions,
|
||||
dataPlacement: 'top',
|
||||
dataContainer: 'body',
|
||||
'class': 'btn-xs btn-help',
|
||||
awToolTip: 'Click for help',
|
||||
dataTitle: 'Help',
|
||||
iconSize: 'fa-lg'
|
||||
};
|
||||
//html += this.button(btn, 'select');
|
||||
html += this.button({
|
||||
btn: btn,
|
||||
action: 'help',
|
||||
toolbar: true
|
||||
});
|
||||
}
|
||||
|
||||
html += "</div><!-- list-acitons -->\n";
|
||||
html += "</div><!-- list-actions-column -->\n";
|
||||
} else {
|
||||
//lookup
|
||||
html += "<div class=\"col-lg-7\"></div>\n";
|
||||
}
|
||||
|
||||
html += "</div><!-- row -->\n";
|
||||
|
||||
// Add a title and optionally a close button (used on Inventory->Groups)
|
||||
if (options.mode !== 'lookup' && list.showTitle) {
|
||||
html += "<div class=\"form-title\">";
|
||||
html += (options.mode === 'edit' || options.mode === 'summary') ? list.editTitle : list.addTitle;
|
||||
html += "</div>\n";
|
||||
}
|
||||
|
||||
// table header row
|
||||
html += "<table id=\"" + list.name + "_table\" ";
|
||||
html += "class=\"table";
|
||||
html += (list['class']) ? " " + list['class'] : "";
|
||||
html += (options.mode !== 'summary' && options.mode !== 'edit' && (options.mode === 'lookup' || options.id)) ?
|
||||
' table-hover-inverse' : '';
|
||||
html += (list.hover) ? ' table-hover' : '';
|
||||
html += (options.mode === 'summary') ? ' table-summary' : '';
|
||||
html += "\" ";
|
||||
html += ">\n";
|
||||
html += "<thead>\n";
|
||||
html += "<tr>\n";
|
||||
if (list.index) {
|
||||
html += "<th class=\"col-lg-1 col-md-1 col-sm-1 hidden-xs\">#</th>\n";
|
||||
}
|
||||
for (fld in list.fields) {
|
||||
if ((list.fields[fld].searchOnly === undefined || list.fields[fld].searchOnly === false) &&
|
||||
!(options.mode === 'lookup' && list.fields[fld].excludeModal !== undefined && list.fields[fld].excludeModal === true)) {
|
||||
html += "<th class=\"list-header";
|
||||
html += (list.fields[fld].columnClass) ? " " + list.fields[fld].columnClass : "";
|
||||
html += "\" id=\"";
|
||||
html += (list.fields[fld].id) ? list.fields[fld].id : fld + "-header";
|
||||
html += "\"";
|
||||
html += (list.fields[fld].columnShow) ? " ng-show=\"" + list.fields[fld].columnShow + "\" " : "";
|
||||
html += (list.fields[fld].nosort === undefined || list.fields[fld].nosort !== true) ? "ng-click=\"sort('" + fld + "')\"" : "";
|
||||
html += ">";
|
||||
html += list.fields[fld].label;
|
||||
if (list.fields[fld].nosort === undefined || list.fields[fld].nosort !== true) {
|
||||
html += " <i class=\"fa ";
|
||||
if (list.fields[fld].key) {
|
||||
if (list.fields[fld].desc) {
|
||||
html += "fa-sort-down";
|
||||
} else {
|
||||
html += "fa-sort-up";
|
||||
}
|
||||
} else {
|
||||
html += "fa-sort";
|
||||
}
|
||||
html += "\"></i></a>";
|
||||
}
|
||||
html += "</th>\n";
|
||||
}
|
||||
}
|
||||
if (options.mode === 'select' || options.mode === 'lookup') {
|
||||
html += "<th>Select</th>";
|
||||
} else if (options.mode === 'edit' && list.fieldActions) {
|
||||
html += "<th class=\"actions-column";
|
||||
html += (list.fieldActions && list.fieldActions.columnClass) ? " " + list.fieldActions.columnClass : "";
|
||||
html += "\">Actions</th>\n";
|
||||
}
|
||||
html += "</tr>\n";
|
||||
html += "</thead>\n";
|
||||
|
||||
// table body
|
||||
html += "<tbody>\n";
|
||||
html += "<tr ng-class=\"" + list.iterator;
|
||||
html += (options.mode === 'lookup' || options.mode === 'select') ? ".success_class" : ".active_class";
|
||||
html += "\" ";
|
||||
html += "class=\"" + list.iterator + "_class\" ng-repeat=\"" + list.iterator + " in " + list.name;
|
||||
html += (list.orderBy) ? " | orderBy:'" + list.orderBy + "'" : "";
|
||||
html += (list.filterBy) ? " | filter: " + list.filterBy : "";
|
||||
html += "\"";
|
||||
html += ">\n";
|
||||
if (list.index) {
|
||||
html += "<td class=\"index-column hidden-xs\">{{ $index + ((" + list.iterator + "_page - 1) * " + list.iterator + "_page_size) + 1 }}.</td>\n";
|
||||
}
|
||||
cnt = 2;
|
||||
base = (list.base) ? list.base : list.name;
|
||||
base = base.replace(/^\//, '');
|
||||
for (fld in list.fields) {
|
||||
cnt++;
|
||||
if ((list.fields[fld].searchOnly === undefined || list.fields[fld].searchOnly === false) &&
|
||||
!(options.mode === 'lookup' && list.fields[fld].excludeModal !== undefined &&
|
||||
list.fields[fld].excludeModal === true)) {
|
||||
html += Column({
|
||||
list: list,
|
||||
fld: fld,
|
||||
options: options,
|
||||
base: base
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (options.mode === 'select' || options.mode === 'lookup') {
|
||||
html += "<td><input type=\"checkbox\" ng-model=\"" + list.iterator + ".checked\" name=\"check_{{" +
|
||||
list.iterator + ".id }}\" ng-click=\"toggle_" + list.iterator + "({{ " + list.iterator + ".id }}, true)\" ng-true-value=\"1\" " +
|
||||
"ng-false-value=\"0\" id=\"check_{{" + list.iterator + ".id}}\" /></td>";
|
||||
} else if ((options.mode === 'edit' || options.mode === 'summary') && list.fieldActions) {
|
||||
|
||||
// Row level actions
|
||||
|
||||
html += "<td class=\"actions\">";
|
||||
|
||||
for (field_action in list.fieldActions) {
|
||||
if (field_action !== 'columnClass') {
|
||||
if (list.fieldActions[field_action].type && list.fieldActions[field_action].type === 'DropDown') {
|
||||
html += DropDown({
|
||||
list: list,
|
||||
fld: field_action,
|
||||
options: options,
|
||||
base: base,
|
||||
type: 'fieldActions',
|
||||
td: false
|
||||
});
|
||||
} else {
|
||||
fAction = list.fieldActions[field_action];
|
||||
html += "<a ";
|
||||
html += (fAction.href) ? "href=\"" + fAction.href + "\" " : "";
|
||||
html += (fAction.ngHref) ? "ng-href=\"" + fAction.ngHref + "\" " : "";
|
||||
html += (field_action === 'cancel') ? "class=\"cancel red-txt\" " : "";
|
||||
html += (fAction.awPopOver) ? "aw-pop-over=\"" + fAction.awPopOver + "\" " : "";
|
||||
html += (fAction.dataPlacement) ? Attr(fAction, 'dataPlacement') : "";
|
||||
html += (fAction.dataTitle) ? Attr(fAction, 'dataTitle') : "";
|
||||
for (itm in fAction) {
|
||||
if (itm !== 'ngHref' && itm !== 'href' && itm !== 'label' && itm !== 'icon' && itm !== 'class' &&
|
||||
itm !== 'iconClass' && itm !== "dataPlacement" && itm !== "awPopOver" && itm !== "dataTitle") {
|
||||
html += Attr(fAction, itm);
|
||||
}
|
||||
}
|
||||
html += ">";
|
||||
if (fAction.iconClass) {
|
||||
html += "<i class=\"" + fAction.iconClass + "\"></i>";
|
||||
} else {
|
||||
html += SelectIcon({
|
||||
action: field_action
|
||||
});
|
||||
}
|
||||
html += (fAction.label) ? " " + list.fieldActions[field_action].label : "";
|
||||
html += "</a>";
|
||||
}
|
||||
}
|
||||
}
|
||||
html += "</td>";
|
||||
}
|
||||
html += "</tr>\n";
|
||||
|
||||
// Message for when a collection is empty
|
||||
html += "<tr class=\"info\" ng-show=\"" + list.iterator + "Loading == false && (" + list.name + " == null || " + list.name + ".length == 0)\">\n";
|
||||
html += "<td colspan=\"" + cnt + "\"><div class=\"alert alert-info\">No records matched your search.</div></td>\n";
|
||||
html += "</tr>\n";
|
||||
|
||||
// Message for loading
|
||||
html += "<tr class=\"info\" ng-show=\"" + list.iterator + "Loading == true\">\n";
|
||||
html += "<td colspan=\"" + cnt + "\"><div class=\"alert alert-info\">Loading...</div></td>\n";
|
||||
html += "</tr>\n";
|
||||
|
||||
// End List
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
|
||||
if (options.mode === 'select' && (options.selectButton === undefined || options.selectButton)) {
|
||||
html += "<div class=\"navigation-buttons\">\n";
|
||||
html += " <button class=\"btn btn-sm btn-primary pull-right\" aw-tool-tip=\"Complete your selection\" " +
|
||||
"ng-click=\"finishSelection()\" ng-disabled=\"disableSelectBtn\"><i class=\"fa fa-check\"></i> Select</button>\n";
|
||||
html += "</div>\n";
|
||||
}
|
||||
|
||||
if (options.mode !== 'lookup' && (list.well === undefined || list.well === true)) {
|
||||
html += "</div>\n"; //well
|
||||
}
|
||||
|
||||
if (list.name !== 'groups') {
|
||||
if (options.mode === 'lookup' || (options.id && options.id === "form-modal-body")) {
|
||||
html += PaginateWidget({
|
||||
set: list.name,
|
||||
iterator: list.iterator
|
||||
});
|
||||
} else {
|
||||
html += PaginateWidget({
|
||||
set: list.name,
|
||||
iterator: list.iterator
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
html += "</th>\n";
|
||||
}
|
||||
}
|
||||
if (options.mode == 'select' || options.mode == 'lookup') {
|
||||
html += "<th>Select</th>";
|
||||
}
|
||||
else if (options.mode == 'edit' && list.fieldActions) {
|
||||
html += "<th class=\"actions-column";
|
||||
html += (list.fieldActions && list.fieldActions.columnClass) ? " " + list.fieldActions.columnClass : "";
|
||||
html += "\">Actions</th>\n";
|
||||
}
|
||||
html += "</tr>\n";
|
||||
html += "</thead>\n";
|
||||
|
||||
// table body
|
||||
html += "<tbody>\n";
|
||||
html += "<tr ng-class=\"" + list.iterator;
|
||||
html += (options.mode == 'lookup' || options.mode == 'select') ? ".success_class" : ".active_class";
|
||||
html += "\" ";
|
||||
html += "class=\"" + list.iterator + "_class\" ng-repeat=\"" + list.iterator + " in " + list.name;
|
||||
html += (list.orderBy) ? " | orderBy:'" + list.orderBy + "'" : "";
|
||||
html += (list.filterBy) ? " | filter: " + list.filterBy : "";
|
||||
html += "\"";
|
||||
html += ">\n";
|
||||
if (list.index) {
|
||||
html += "<td class=\"index-column hidden-xs\">{{ $index + ((" + list.iterator + "_page - 1) * " + list.iterator + "_page_size) + 1 }}.</td>\n";
|
||||
}
|
||||
var cnt = 2;
|
||||
var base = (list.base) ? list.base : list.name;
|
||||
base = base.replace(/^\//,'');
|
||||
for (fld in list.fields) {
|
||||
cnt++;
|
||||
if ( (list.fields[fld].searchOnly == undefined || list.fields[fld].searchOnly == false) &&
|
||||
!(options.mode == 'lookup' && list.fields[fld].excludeModal !== undefined && list.fields[fld].excludeModal == true) ) {
|
||||
html += Column({ list: list, fld: fld, options: options, base: base });
|
||||
}
|
||||
}
|
||||
|
||||
if (options.mode == 'select' || options.mode == 'lookup') {
|
||||
html += "<td><input type=\"checkbox\" ng-model=\"" + list.iterator + ".checked\" name=\"check_{{" +
|
||||
list.iterator + ".id }}\" ng-click=\"toggle_" + list.iterator +"({{ " + list.iterator + ".id }}, true)\" ng-true-value=\"1\" " +
|
||||
"ng-false-value=\"0\" id=\"check_{{" + list.iterator + ".id}}\" /></td>";
|
||||
}
|
||||
else if ((options.mode == 'edit' || options.mode == 'summary') && list.fieldActions) {
|
||||
|
||||
// Row level actions
|
||||
|
||||
html += "<td class=\"actions\">";
|
||||
|
||||
var field_action, fAction, itm;
|
||||
|
||||
for (field_action in list.fieldActions) {
|
||||
if (field_action !== 'columnClass') {
|
||||
if (list.fieldActions[field_action].type && list.fieldActions[field_action].type == 'DropDown') {
|
||||
html += DropDown({
|
||||
list: list,
|
||||
fld: field_action,
|
||||
options: options,
|
||||
base: base,
|
||||
type: 'fieldActions',
|
||||
td: false
|
||||
});
|
||||
}
|
||||
else {
|
||||
fAction = list.fieldActions[field_action];
|
||||
html += "<a ";
|
||||
html += (fAction.href) ? "href=\"" + fAction.href + "\" " : "";
|
||||
html += (fAction.ngHref) ? "ng-href=\"" + fAction.ngHref + "\" " : "";
|
||||
html += (field_action == 'cancel') ? "class=\"cancel red-txt\" " : "";
|
||||
html += (fAction.awPopOver) ? "aw-pop-over=\"" + fAction.awPopOver + "\" " : "";
|
||||
html += (fAction.dataPlacement) ? Attr(fAction, 'dataPlacement') : "";
|
||||
html += (fAction.dataTitle) ? Attr(fAction, 'dataTitle') : "";
|
||||
for (itm in fAction) {
|
||||
if (itm != 'ngHref' && itm != 'href' && itm != 'label' && itm != 'icon' && itm != 'class' &&
|
||||
itm != 'iconClass' && itm != "dataPlacement" && itm != "awPopOver" && itm != "dataTitle") {
|
||||
html += Attr(fAction, itm);
|
||||
}
|
||||
}
|
||||
html += ">";
|
||||
if (fAction.iconClass) {
|
||||
html += "<i class=\"" + fAction.iconClass + "\"></i>";
|
||||
}
|
||||
else {
|
||||
html += SelectIcon({ action: field_action });
|
||||
}
|
||||
html += (fAction.label) ? " " + list.fieldActions[field_action]['label'] : "";
|
||||
html += "</a>";
|
||||
}
|
||||
}
|
||||
}
|
||||
html += "</td>";
|
||||
}
|
||||
html += "</tr>\n";
|
||||
|
||||
// Message for when a collection is empty
|
||||
html += "<tr class=\"info\" ng-show=\"" + list.iterator + "Loading == false && (" + list.name + " == null || " + list.name + ".length == 0)\">\n";
|
||||
html += "<td colspan=\"" + cnt + "\"><div class=\"alert alert-info\">No records matched your search.</div></td>\n";
|
||||
html += "</tr>\n";
|
||||
|
||||
// Message for loading
|
||||
html += "<tr class=\"info\" ng-show=\"" + list.iterator + "Loading == true\">\n";
|
||||
html += "<td colspan=\"" + cnt + "\"><div class=\"alert alert-info\">Loading...</div></td>\n";
|
||||
html += "</tr>\n";
|
||||
|
||||
// End List
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
|
||||
if (options.mode == 'select' && (options.selectButton == undefined || options.selectButton == true)) {
|
||||
html += "<div class=\"navigation-buttons\">\n";
|
||||
html += " <button class=\"btn btn-sm btn-primary pull-right\" aw-tool-tip=\"Complete your selection\" " +
|
||||
"ng-click=\"finishSelection()\" ng-disabled=\"disableSelectBtn\"><i class=\"fa fa-check\"></i> Select</button>\n";
|
||||
html += "</div>\n";
|
||||
}
|
||||
|
||||
if (options.mode != 'lookup' && (list.well == undefined || list.well == true)) {
|
||||
html += "</div>\n"; //well
|
||||
}
|
||||
|
||||
if (list.name !== 'groups') {
|
||||
if ( options.mode == 'lookup' || (options.id && options.id == "form-modal-body") ) {
|
||||
html += PaginateWidget({ set: list.name, iterator: list.iterator });
|
||||
}
|
||||
else {
|
||||
html += PaginateWidget({ set: list.name, iterator: list.iterator });
|
||||
}
|
||||
}
|
||||
|
||||
return html;
|
||||
|
||||
}
|
||||
|
||||
}}]);
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -2,12 +2,12 @@
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* PromptDialog
|
||||
* Prompt the user with a Yes/No dialog to confirm an action such
|
||||
* Prompt the user with a Yes/No dialog to confirm an action such
|
||||
* as Delete. Assumes a hidden dialog already exists in $scope.
|
||||
* See example at bottom. If user responds with Yes, execute action
|
||||
* See example at bottom. If user responds with Yes, execute action
|
||||
* parameter.
|
||||
*
|
||||
* params: { hdr: 'header msg',
|
||||
* params: { hdr: 'header msg',
|
||||
* body: 'body text/html',
|
||||
* class: 'btn-class for Yes button', --defaults to btn-danger
|
||||
* action: function() {} --action to take, if use clicks Yes
|
||||
@ -17,25 +17,26 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('PromptDialog', ['Utilities'])
|
||||
.factory('Prompt', ['$rootScope', '$compile', 'Alert', function($rootScope, $compile, Alert) {
|
||||
return function(params) {
|
||||
|
||||
var dialog = angular.element(document.getElementById('prompt-modal'));
|
||||
var scope = dialog.scope();
|
||||
|
||||
scope.promptHeader = params.hdr;
|
||||
scope.promptBody = params.body;
|
||||
scope.promptAction = params.action;
|
||||
|
||||
var cls = (params['class'] == null || params['class'] == undefined) ? 'btn-danger' : params['class'];
|
||||
|
||||
$('#prompt_action_btn').removeClass(cls).addClass(cls);
|
||||
|
||||
$(dialog).modal({
|
||||
backdrop: 'static',
|
||||
keyboard: true,
|
||||
show: true
|
||||
});
|
||||
.factory('Prompt', [
|
||||
function () {
|
||||
return function (params) {
|
||||
|
||||
var dialog = angular.element(document.getElementById('prompt-modal')),
|
||||
scope = dialog.scope(), cls;
|
||||
|
||||
scope.promptHeader = params.hdr;
|
||||
scope.promptBody = params.body;
|
||||
scope.promptAction = params.action;
|
||||
|
||||
cls = (params['class'] === null || params['class'] === undefined) ? 'btn-danger' : params['class'];
|
||||
|
||||
$('#prompt_action_btn').removeClass(cls).addClass(cls);
|
||||
|
||||
$(dialog).modal({
|
||||
backdrop: 'static',
|
||||
keyboard: true,
|
||||
show: true
|
||||
});
|
||||
};
|
||||
}
|
||||
}]);
|
||||
|
||||
]);
|
||||
@ -22,205 +22,294 @@
|
||||
** 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
**
|
||||
**
|
||||
** CLH 9/5/13 - Set required strength in config.js
|
||||
** CLH 09/05/13 - Set required strength in config.js
|
||||
** 02/10/14 - Applied jsHint
|
||||
*/
|
||||
|
||||
String.prototype.strReverse = function() {
|
||||
var newstring = "";
|
||||
for (var s=0; s < this.length; s++) {
|
||||
newstring = this.charAt(s) + newstring;
|
||||
}
|
||||
return newstring;
|
||||
/*jshint eqeqeq:false, unused:false */
|
||||
|
||||
String.prototype.strReverse = function () {
|
||||
var newstring = "", s;
|
||||
for (s = 0; s < this.length; s++) {
|
||||
newstring = this.charAt(s) + newstring;
|
||||
}
|
||||
return newstring;
|
||||
};
|
||||
|
||||
var nScore = 0;
|
||||
|
||||
function chkPass(pwd) {
|
||||
// Simultaneous variable declaration and value assignment aren't supported in IE apparently
|
||||
// so I'm forced to assign the same value individually per var to support a crappy browser *sigh*
|
||||
var nLength=0, nAlphaUC=0, nAlphaLC=0, nNumber=0, nSymbol=0, nMidChar=0, nRequirements=0,
|
||||
nAlphasOnly=0, nNumbersOnly=0, nUnqChar=0, nRepChar=0, nRepInc=0, nConsecAlphaUC=0, nConsecAlphaLC=0,
|
||||
nConsecNumber=0, nConsecSymbol=0, nConsecCharType=0, nSeqAlpha=0, nSeqNumber=0, nSeqSymbol=0,
|
||||
nSeqChar=0, nReqChar=0, nMultConsecCharType=0;
|
||||
var nMultRepChar=1, nMultConsecSymbol=1;
|
||||
var nMultMidChar=2, nMultRequirements=2, nMultConsecAlphaUC=2, nMultConsecAlphaLC=2, nMultConsecNumber=2;
|
||||
var nReqCharType=3, nMultAlphaUC=3, nMultAlphaLC=3, nMultSeqAlpha=3, nMultSeqNumber=3, nMultSeqSymbol=3;
|
||||
var nMultLength=4, nMultNumber=4;
|
||||
var nMultSymbol=6;
|
||||
var nTmpAlphaUC="", nTmpAlphaLC="", nTmpNumber="", nTmpSymbol="";
|
||||
var sAlphaUC="0", sAlphaLC="0", sNumber="0", sSymbol="0", sMidChar="0", sRequirements="0",
|
||||
sAlphasOnly="0", sNumbersOnly="0", sRepChar="0", sConsecAlphaUC="0", sConsecAlphaLC="0",
|
||||
sConsecNumber="0", sSeqAlpha="0", sSeqNumber="0", sSeqSymbol="0";
|
||||
var sAlphas = "abcdefghijklmnopqrstuvwxyz";
|
||||
var sNumerics = "01234567890";
|
||||
var sSymbols = ")_!@#$%^&*()";
|
||||
var sComplexity = "Too Short";
|
||||
var sStandards = "Below";
|
||||
var nMinPwdLen = 8;
|
||||
if (document.all) { var nd = 0; } else { var nd = 1; }
|
||||
if (pwd) {
|
||||
nScore = parseInt(pwd.length * nMultLength);
|
||||
nLength = pwd.length;
|
||||
var arrPwd = pwd.replace(/\s+/g,"").split(/\s*/);
|
||||
var arrPwdLen = arrPwd.length;
|
||||
|
||||
/* Loop through password to check for Symbol, Numeric, Lowercase and Uppercase pattern matches */
|
||||
for (var a=0; a < arrPwdLen; a++) {
|
||||
if (arrPwd[a].match(/[A-Z]/g)) {
|
||||
if (nTmpAlphaUC !== "") { if ((nTmpAlphaUC + 1) == a) { nConsecAlphaUC++; nConsecCharType++; } }
|
||||
nTmpAlphaUC = a;
|
||||
nAlphaUC++;
|
||||
}
|
||||
else if (arrPwd[a].match(/[a-z]/g)) {
|
||||
if (nTmpAlphaLC !== "") { if ((nTmpAlphaLC + 1) == a) { nConsecAlphaLC++; nConsecCharType++; } }
|
||||
nTmpAlphaLC = a;
|
||||
nAlphaLC++;
|
||||
}
|
||||
else if (arrPwd[a].match(/[0-9]/g)) {
|
||||
if (a > 0 && a < (arrPwdLen - 1)) { nMidChar++; }
|
||||
if (nTmpNumber !== "") { if ((nTmpNumber + 1) == a) { nConsecNumber++; nConsecCharType++; } }
|
||||
nTmpNumber = a;
|
||||
nNumber++;
|
||||
}
|
||||
else if (arrPwd[a].match(/[^a-zA-Z0-9_]/g)) {
|
||||
if (a > 0 && a < (arrPwdLen - 1)) { nMidChar++; }
|
||||
if (nTmpSymbol !== "") { if ((nTmpSymbol + 1) == a) { nConsecSymbol++; nConsecCharType++; } }
|
||||
nTmpSymbol = a;
|
||||
nSymbol++;
|
||||
}
|
||||
/* Internal loop through password to check for repeat characters */
|
||||
var bCharExists = false;
|
||||
for (var b=0; b < arrPwdLen; b++) {
|
||||
if (arrPwd[a] == arrPwd[b] && a != b) { /* repeat character exists */
|
||||
bCharExists = true;
|
||||
/*
|
||||
// Simultaneous variable declaration and value assignment aren't supported in IE apparently
|
||||
// so I'm forced to assign the same value individually per var to support a crappy browser *sigh*
|
||||
var nLength = 0,
|
||||
nAlphaUC = 0,
|
||||
nAlphaLC = 0,
|
||||
nNumber = 0,
|
||||
nSymbol = 0,
|
||||
nMidChar = 0,
|
||||
nRequirements = 0,
|
||||
nAlphasOnly = 0,
|
||||
nNumbersOnly = 0,
|
||||
nUnqChar = 0,
|
||||
nRepChar = 0,
|
||||
nRepInc = 0,
|
||||
nConsecAlphaUC = 0,
|
||||
nConsecAlphaLC = 0,
|
||||
nConsecNumber = 0,
|
||||
nConsecSymbol = 0,
|
||||
nConsecCharType = 0,
|
||||
nSeqAlpha = 0,
|
||||
nSeqNumber = 0,
|
||||
nSeqSymbol = 0,
|
||||
nSeqChar = 0,
|
||||
nReqChar = 0,
|
||||
nMultConsecCharType = 0,
|
||||
nMultRepChar = 1,
|
||||
nMultConsecSymbol = 1,
|
||||
nMultMidChar = 2,
|
||||
nMultRequirements = 2,
|
||||
nMultConsecAlphaUC = 2,
|
||||
nMultConsecAlphaLC = 2,
|
||||
nMultConsecNumber = 2,
|
||||
nReqCharType = 3,
|
||||
nMultAlphaUC = 3,
|
||||
nMultAlphaLC = 3,
|
||||
nMultSeqAlpha = 3,
|
||||
nMultSeqNumber = 3,
|
||||
nMultSeqSymbol = 3,
|
||||
nMultLength = 4,
|
||||
nMultNumber = 4,
|
||||
nMultSymbol = 6,
|
||||
nTmpAlphaUC = "",
|
||||
nTmpAlphaLC = "",
|
||||
nTmpNumber = "",
|
||||
nTmpSymbol = "",
|
||||
sAlphaUC = "0",
|
||||
sAlphaLC = "0",
|
||||
sNumber = "0",
|
||||
sSymbol = "0",
|
||||
sMidChar = "0",
|
||||
sRequirements = "0",
|
||||
sAlphasOnly = "0",
|
||||
sNumbersOnly = "0",
|
||||
sRepChar = "0",
|
||||
sConsecAlphaUC = "0",
|
||||
sConsecAlphaLC = "0",
|
||||
sConsecNumber = "0",
|
||||
sSeqAlpha = "0",
|
||||
sSeqNumber = "0",
|
||||
sSeqSymbol = "0",
|
||||
sAlphas = "abcdefghijklmnopqrstuvwxyz",
|
||||
sNumerics = "01234567890",
|
||||
sSymbols = ")_!@#$%^&*()",
|
||||
sComplexity = "Too Short",
|
||||
sStandards = "Below",
|
||||
nMinPwdLen = 8,
|
||||
a, nd, arrPwd, arrPwdLen,bCharExists,b,s,sFwd,sRev,progbar,required_strength,warning_level;
|
||||
|
||||
if (document.all) {
|
||||
nd = 0;
|
||||
} else {
|
||||
nd = 1;
|
||||
}
|
||||
if (pwd) {
|
||||
nScore = parseInt(pwd.length * nMultLength);
|
||||
nLength = pwd.length;
|
||||
arrPwd = pwd.replace(/\s+/g, "").split(/\s*/);
|
||||
arrPwdLen = arrPwd.length;
|
||||
|
||||
/* Loop through password to check for Symbol, Numeric, Lowercase and Uppercase pattern matches */
|
||||
for (a = 0; a < arrPwdLen; a++) {
|
||||
if (arrPwd[a].match(/[A-Z]/g)) {
|
||||
if (nTmpAlphaUC !== "") {
|
||||
if ((nTmpAlphaUC + 1) == a) {
|
||||
nConsecAlphaUC++;
|
||||
nConsecCharType++;
|
||||
}
|
||||
}
|
||||
nTmpAlphaUC = a;
|
||||
nAlphaUC++;
|
||||
} else if (arrPwd[a].match(/[a-z]/g)) {
|
||||
if (nTmpAlphaLC !== "") {
|
||||
if ((nTmpAlphaLC + 1) == a) {
|
||||
nConsecAlphaLC++;
|
||||
nConsecCharType++;
|
||||
}
|
||||
}
|
||||
nTmpAlphaLC = a;
|
||||
nAlphaLC++;
|
||||
} else if (arrPwd[a].match(/[0-9]/g)) {
|
||||
if (a > 0 && a < (arrPwdLen - 1)) {
|
||||
nMidChar++;
|
||||
}
|
||||
if (nTmpNumber !== "") {
|
||||
if ((nTmpNumber + 1) == a) {
|
||||
nConsecNumber++;
|
||||
nConsecCharType++;
|
||||
}
|
||||
}
|
||||
nTmpNumber = a;
|
||||
nNumber++;
|
||||
} else if (arrPwd[a].match(/[^a-zA-Z0-9_]/g)) {
|
||||
if (a > 0 && a < (arrPwdLen - 1)) {
|
||||
nMidChar++;
|
||||
}
|
||||
if (nTmpSymbol !== "") {
|
||||
if ((nTmpSymbol + 1) == a) {
|
||||
nConsecSymbol++;
|
||||
nConsecCharType++;
|
||||
}
|
||||
}
|
||||
nTmpSymbol = a;
|
||||
nSymbol++;
|
||||
}
|
||||
|
||||
/* Internal loop through password to check for repeat characters */
|
||||
bCharExists = false;
|
||||
for (b = 0; b < arrPwdLen; b++) {
|
||||
if (arrPwd[a] == arrPwd[b] && a != b) { /* repeat character exists */
|
||||
bCharExists = true;
|
||||
/*
|
||||
Calculate icrement deduction based on proximity to identical characters
|
||||
Deduction is incremented each time a new match is discovered
|
||||
Deduction amount is based on total password length divided by the
|
||||
difference of distance between currently selected match
|
||||
*/
|
||||
nRepInc += Math.abs(arrPwdLen/(b-a));
|
||||
nRepInc += Math.abs(arrPwdLen / (b - a));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bCharExists) {
|
||||
nRepChar++;
|
||||
nUnqChar = arrPwdLen-nRepChar;
|
||||
nRepInc = (nUnqChar) ? Math.ceil(nRepInc/nUnqChar) : Math.ceil(nRepInc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for sequential alpha string patterns (forward and reverse) */
|
||||
for (var s=0; s < 23; s++) {
|
||||
var sFwd = sAlphas.substring(s,parseInt(s+3));
|
||||
var sRev = sFwd.strReverse();
|
||||
if (pwd.toLowerCase().indexOf(sFwd) != -1 || pwd.toLowerCase().indexOf(sRev) != -1) { nSeqAlpha++; nSeqChar++;}
|
||||
}
|
||||
|
||||
/* Check for sequential numeric string patterns (forward and reverse) */
|
||||
for (var s=0; s < 8; s++) {
|
||||
var sFwd = sNumerics.substring(s,parseInt(s+3));
|
||||
var sRev = sFwd.strReverse();
|
||||
if (pwd.toLowerCase().indexOf(sFwd) != -1 || pwd.toLowerCase().indexOf(sRev) != -1) { nSeqNumber++; nSeqChar++;}
|
||||
}
|
||||
|
||||
/* Check for sequential symbol string patterns (forward and reverse) */
|
||||
for (var s=0; s < 8; s++) {
|
||||
var sFwd = sSymbols.substring(s,parseInt(s+3));
|
||||
var sRev = sFwd.strReverse();
|
||||
if (pwd.toLowerCase().indexOf(sFwd) != -1 || pwd.toLowerCase().indexOf(sRev) != -1) { nSeqSymbol++; nSeqChar++;}
|
||||
}
|
||||
|
||||
/* Modify overall score value based on usage vs requirements */
|
||||
if (bCharExists) {
|
||||
nRepChar++;
|
||||
nUnqChar = arrPwdLen - nRepChar;
|
||||
nRepInc = (nUnqChar) ? Math.ceil(nRepInc / nUnqChar) : Math.ceil(nRepInc);
|
||||
}
|
||||
}
|
||||
|
||||
/* General point assignment */
|
||||
if (nAlphaUC > 0 && nAlphaUC < nLength) {
|
||||
nScore = parseInt(nScore + ((nLength - nAlphaUC) * 2));
|
||||
sAlphaUC = "+ " + parseInt((nLength - nAlphaUC) * 2);
|
||||
}
|
||||
if (nAlphaLC > 0 && nAlphaLC < nLength) {
|
||||
nScore = parseInt(nScore + ((nLength - nAlphaLC) * 2));
|
||||
sAlphaLC = "+ " + parseInt((nLength - nAlphaLC) * 2);
|
||||
}
|
||||
if (nNumber > 0 && nNumber < nLength) {
|
||||
nScore = parseInt(nScore + (nNumber * nMultNumber));
|
||||
sNumber = "+ " + parseInt(nNumber * nMultNumber);
|
||||
}
|
||||
if (nSymbol > 0) {
|
||||
nScore = parseInt(nScore + (nSymbol * nMultSymbol));
|
||||
sSymbol = "+ " + parseInt(nSymbol * nMultSymbol);
|
||||
}
|
||||
if (nMidChar > 0) {
|
||||
nScore = parseInt(nScore + (nMidChar * nMultMidChar));
|
||||
sMidChar = "+ " + parseInt(nMidChar * nMultMidChar);
|
||||
}
|
||||
/* Check for sequential alpha string patterns (forward and reverse) */
|
||||
for (s = 0; s < 23; s++) {
|
||||
sFwd = sAlphas.substring(s, parseInt(s + 3));
|
||||
sRev = sFwd.strReverse();
|
||||
if (pwd.toLowerCase().indexOf(sFwd) != -1 || pwd.toLowerCase().indexOf(sRev) != -1) {
|
||||
nSeqAlpha++;
|
||||
nSeqChar++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Point deductions for poor practices */
|
||||
if ((nAlphaLC > 0 || nAlphaUC > 0) && nSymbol === 0 && nNumber === 0) { // Only Letters
|
||||
nScore = parseInt(nScore - nLength);
|
||||
nAlphasOnly = nLength;
|
||||
sAlphasOnly = "- " + nLength;
|
||||
}
|
||||
if (nAlphaLC === 0 && nAlphaUC === 0 && nSymbol === 0 && nNumber > 0) { // Only Numbers
|
||||
nScore = parseInt(nScore - nLength);
|
||||
nNumbersOnly = nLength;
|
||||
sNumbersOnly = "- " + nLength;
|
||||
}
|
||||
if (nRepChar > 0) { // Same character exists more than once
|
||||
nScore = parseInt(nScore - nRepInc);
|
||||
sRepChar = "- " + nRepInc;
|
||||
}
|
||||
if (nConsecAlphaUC > 0) { // Consecutive Uppercase Letters exist
|
||||
nScore = parseInt(nScore - (nConsecAlphaUC * nMultConsecAlphaUC));
|
||||
sConsecAlphaUC = "- " + parseInt(nConsecAlphaUC * nMultConsecAlphaUC);
|
||||
}
|
||||
if (nConsecAlphaLC > 0) { // Consecutive Lowercase Letters exist
|
||||
nScore = parseInt(nScore - (nConsecAlphaLC * nMultConsecAlphaLC));
|
||||
sConsecAlphaLC = "- " + parseInt(nConsecAlphaLC * nMultConsecAlphaLC);
|
||||
}
|
||||
if (nConsecNumber > 0) { // Consecutive Numbers exist
|
||||
nScore = parseInt(nScore - (nConsecNumber * nMultConsecNumber));
|
||||
sConsecNumber = "- " + parseInt(nConsecNumber * nMultConsecNumber);
|
||||
}
|
||||
if (nSeqAlpha > 0) { // Sequential alpha strings exist (3 characters or more)
|
||||
nScore = parseInt(nScore - (nSeqAlpha * nMultSeqAlpha));
|
||||
sSeqAlpha = "- " + parseInt(nSeqAlpha * nMultSeqAlpha);
|
||||
}
|
||||
if (nSeqNumber > 0) { // Sequential numeric strings exist (3 characters or more)
|
||||
nScore = parseInt(nScore - (nSeqNumber * nMultSeqNumber));
|
||||
sSeqNumber = "- " + parseInt(nSeqNumber * nMultSeqNumber);
|
||||
}
|
||||
if (nSeqSymbol > 0) { // Sequential symbol strings exist (3 characters or more)
|
||||
nScore = parseInt(nScore - (nSeqSymbol * nMultSeqSymbol));
|
||||
sSeqSymbol = "- " + parseInt(nSeqSymbol * nMultSeqSymbol);
|
||||
}
|
||||
/* Check for sequential numeric string patterns (forward and reverse) */
|
||||
for (s = 0; s < 8; s++) {
|
||||
sFwd = sNumerics.substring(s, parseInt(s + 3));
|
||||
sRev = sFwd.strReverse();
|
||||
if (pwd.toLowerCase().indexOf(sFwd) != -1 || pwd.toLowerCase().indexOf(sRev) != -1) {
|
||||
nSeqNumber++;
|
||||
nSeqChar++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine complexity based on overall score */
|
||||
if (nScore > 100) { nScore = 100; } else if (nScore < 0) { nScore = 0; }
|
||||
/* Check for sequential symbol string patterns (forward and reverse) */
|
||||
for (s = 0; s < 8; s++) {
|
||||
sFwd = sSymbols.substring(s, parseInt(s + 3));
|
||||
sRev = sFwd.strReverse();
|
||||
if (pwd.toLowerCase().indexOf(sFwd) != -1 || pwd.toLowerCase().indexOf(sRev) != -1) {
|
||||
nSeqSymbol++;
|
||||
nSeqChar++;
|
||||
}
|
||||
}
|
||||
|
||||
var progbar = $("#progbar");
|
||||
var required_strength = $AnsibleConfig.password_strength;
|
||||
var warning_level = ($AnsibleConfig.password_strength - 15 < 0) ? 0 : $AnsibleConfig.password_strength - 15;
|
||||
/* Modify overall score value based on usage vs requirements */
|
||||
|
||||
progbar.css("width", nScore + '%');
|
||||
/* General point assignment */
|
||||
if (nAlphaUC > 0 && nAlphaUC < nLength) {
|
||||
nScore = parseInt(nScore + ((nLength - nAlphaUC) * 2));
|
||||
sAlphaUC = "+ " + parseInt((nLength - nAlphaUC) * 2);
|
||||
}
|
||||
if (nAlphaLC > 0 && nAlphaLC < nLength) {
|
||||
nScore = parseInt(nScore + ((nLength - nAlphaLC) * 2));
|
||||
sAlphaLC = "+ " + parseInt((nLength - nAlphaLC) * 2);
|
||||
}
|
||||
if (nNumber > 0 && nNumber < nLength) {
|
||||
nScore = parseInt(nScore + (nNumber * nMultNumber));
|
||||
sNumber = "+ " + parseInt(nNumber * nMultNumber);
|
||||
}
|
||||
if (nSymbol > 0) {
|
||||
nScore = parseInt(nScore + (nSymbol * nMultSymbol));
|
||||
sSymbol = "+ " + parseInt(nSymbol * nMultSymbol);
|
||||
}
|
||||
if (nMidChar > 0) {
|
||||
nScore = parseInt(nScore + (nMidChar * nMultMidChar));
|
||||
sMidChar = "+ " + parseInt(nMidChar * nMultMidChar);
|
||||
}
|
||||
|
||||
if (nScore >= 0 && nScore <= warning_level) {
|
||||
sComplexity = 'Weak';
|
||||
progbar.addClass('progress-bar-danger')
|
||||
progbar.removeClass('progress-bar-success progress-bar-warning')
|
||||
} else if (nScore > warning_level && nScore <= required_strength) {
|
||||
sComplexity = 'Good';
|
||||
progbar.addClass('progress-bar-warning')
|
||||
progbar.removeClass('progress-bar-success progress-bar-danger')
|
||||
} else if (nScore > required_strength) {
|
||||
sComplexity = "Strong";
|
||||
progbar.addClass('progress-bar-success')
|
||||
progbar.removeClass('progress-bar-warning progress-bar-danger')
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* no password, so reset the displays */
|
||||
var progbar = $("#progbar");
|
||||
progbar.css("width", '0%');
|
||||
progbar.removeClass('progress-bar-success progress-bar-warning')
|
||||
}
|
||||
return nScore;
|
||||
/* Point deductions for poor practices */
|
||||
if ((nAlphaLC > 0 || nAlphaUC > 0) && nSymbol === 0 && nNumber === 0) { // Only Letters
|
||||
nScore = parseInt(nScore - nLength);
|
||||
nAlphasOnly = nLength;
|
||||
sAlphasOnly = "- " + nLength;
|
||||
}
|
||||
if (nAlphaLC === 0 && nAlphaUC === 0 && nSymbol === 0 && nNumber > 0) { // Only Numbers
|
||||
nScore = parseInt(nScore - nLength);
|
||||
nNumbersOnly = nLength;
|
||||
sNumbersOnly = "- " + nLength;
|
||||
}
|
||||
if (nRepChar > 0) { // Same character exists more than once
|
||||
nScore = parseInt(nScore - nRepInc);
|
||||
sRepChar = "- " + nRepInc;
|
||||
}
|
||||
if (nConsecAlphaUC > 0) { // Consecutive Uppercase Letters exist
|
||||
nScore = parseInt(nScore - (nConsecAlphaUC * nMultConsecAlphaUC));
|
||||
sConsecAlphaUC = "- " + parseInt(nConsecAlphaUC * nMultConsecAlphaUC);
|
||||
}
|
||||
if (nConsecAlphaLC > 0) { // Consecutive Lowercase Letters exist
|
||||
nScore = parseInt(nScore - (nConsecAlphaLC * nMultConsecAlphaLC));
|
||||
sConsecAlphaLC = "- " + parseInt(nConsecAlphaLC * nMultConsecAlphaLC);
|
||||
}
|
||||
if (nConsecNumber > 0) { // Consecutive Numbers exist
|
||||
nScore = parseInt(nScore - (nConsecNumber * nMultConsecNumber));
|
||||
sConsecNumber = "- " + parseInt(nConsecNumber * nMultConsecNumber);
|
||||
}
|
||||
if (nSeqAlpha > 0) { // Sequential alpha strings exist (3 characters or more)
|
||||
nScore = parseInt(nScore - (nSeqAlpha * nMultSeqAlpha));
|
||||
sSeqAlpha = "- " + parseInt(nSeqAlpha * nMultSeqAlpha);
|
||||
}
|
||||
if (nSeqNumber > 0) { // Sequential numeric strings exist (3 characters or more)
|
||||
nScore = parseInt(nScore - (nSeqNumber * nMultSeqNumber));
|
||||
sSeqNumber = "- " + parseInt(nSeqNumber * nMultSeqNumber);
|
||||
}
|
||||
if (nSeqSymbol > 0) { // Sequential symbol strings exist (3 characters or more)
|
||||
nScore = parseInt(nScore - (nSeqSymbol * nMultSeqSymbol));
|
||||
sSeqSymbol = "- " + parseInt(nSeqSymbol * nMultSeqSymbol);
|
||||
}
|
||||
|
||||
/* Determine complexity based on overall score */
|
||||
if (nScore > 100) {
|
||||
nScore = 100;
|
||||
} else if (nScore < 0) {
|
||||
nScore = 0;
|
||||
}
|
||||
|
||||
progbar = $("#progbar");
|
||||
required_strength = $AnsibleConfig.password_strength;
|
||||
warning_level = ($AnsibleConfig.password_strength - 15 < 0) ? 0 : $AnsibleConfig.password_strength - 15;
|
||||
|
||||
progbar.css("width", nScore + '%');
|
||||
|
||||
if (nScore >= 0 && nScore <= warning_level) {
|
||||
sComplexity = 'Weak';
|
||||
progbar.addClass('progress-bar-danger');
|
||||
progbar.removeClass('progress-bar-success progress-bar-warning');
|
||||
} else if (nScore > warning_level && nScore <= required_strength) {
|
||||
sComplexity = 'Good';
|
||||
progbar.addClass('progress-bar-warning');
|
||||
progbar.removeClass('progress-bar-success progress-bar-danger');
|
||||
} else if (nScore > required_strength) {
|
||||
sComplexity = "Strong";
|
||||
progbar.addClass('progress-bar-success');
|
||||
progbar.removeClass('progress-bar-warning progress-bar-danger');
|
||||
}
|
||||
} else {
|
||||
/* no password, so reset the displays */
|
||||
progbar = $("#progbar");
|
||||
progbar.css("width", '0%');
|
||||
progbar.removeClass('progress-bar-success progress-bar-warning');
|
||||
}
|
||||
return nScore;
|
||||
}
|
||||
@ -71,10 +71,11 @@
|
||||
<script src="{{ STATIC_URL }}js/forms/ProjectStatus.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/forms/Permissions.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/forms/JobEventData.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/forms/JobEvents.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/forms/HostGroups.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/forms/InventoryStatus.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/forms/ActivityDetail.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/forms/JobSummary.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/forms/LicenseForm.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/lists/Users.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/lists/Organizations.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/lists/Admins.js"></script>
|
||||
@ -123,7 +124,6 @@
|
||||
<script src="{{ STATIC_URL }}js/widgets/ObjectCount.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/widgets/Stream.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/help/InventoryGroups.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/help/InventoryHosts.js"></script>
|
||||
<script src="{{ STATIC_URL }}lib/less/less-1.4.1.min.js"></script>
|
||||
|
||||
{% endif %}
|
||||
|
||||
9
package.json
Normal file
9
package.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "ansible-commander",
|
||||
"version": "1.4.5",
|
||||
"devDependencies": {
|
||||
"grunt": "latest",
|
||||
"grunt-contrib-jshint": "~0.8.0",
|
||||
"grunt-contrib-uglify": "~0.3.1"
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user