awx/awx/ui/client/src/forms/Projects.js
Jared Tabor 2b3783adf4 Dropdown styling
This uses select2 for styling of the <select> form elements. I'm forcing some styling overrides for select2, therefore we no longer need the select2-bootstrap-theme library.

For all add-forms, select2 is attached after the form compiles in form-generator. For edit-forms however, the select2 module
couldn't be attached to the select element until after the options selection had taken place (which takes place after the REST request). Therefore I had to add some calls to CreateSelect2 in the edit controllers.
2016-02-11 09:15:19 -08:00

378 lines
16 KiB
JavaScript

/*************************************************
* Copyright (c) 2015 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
/**
* @ngdoc function
* @name forms.function:Projects
* @description This form is for adding/editing projects
*/
export default
angular.module('ProjectFormDefinition', ['SchedulesListDefinition'])
.value('ProjectsFormObject', {
addTitle: 'New Project',
editTitle: '{{ name }}',
name: 'project',
forceListeners: true,
tabs: true,
fields: {
name: {
label: 'Name',
type: 'text',
addRequired: true,
editRequired: true,
capitalize: false
},
description: {
label: 'Description',
type: 'text',
addRequired: false,
editRequired: false
},
organization: {
label: 'Organization',
type: 'lookup',
sourceModel: 'organization',
sourceField: 'name',
addRequired: true,
editRequired: false,
excludeMode: 'edit',
ngClick: 'lookUpOrganization()',
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.',
dataTitle: 'Organization',
dataContainer: 'body',
dataPlacement: 'right'
},
scm_type: {
label: 'SCM Type',
type: 'select',
class: 'Form-dropDown--scmType',
ngOptions: 'type.label for type in scm_type_options track by type.value',
ngChange: 'scmChange()',
addRequired: true,
editRequired: true
},
missing_path_alert: {
type: 'alertblock',
"class": 'alert-info',
ngShow: "showMissingPlaybooksAlert && scm_type.value == 'manual'",
alertTxt: '<p class=\"text-justify\"><strong>WARNING:</strong> There are no available playbook directories in {{ base_dir }}. ' +
'Either that directory is empty, or all of the contents are already assigned to other projects. ' +
'Create a new directory there and make sure the playbook files can be read by the "awx" system user, ' +
'or have Tower directly retrieve your playbooks from source control using the SCM Type option above.</p>',
closeable: false
},
base_dir: {
label: 'Project Base Path',
type: 'textarea',
//"class": 'col-lg-6',
showonly: true,
ngShow: "scm_type.value == 'manual' " ,
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>',
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
},
ngShow: "scm_type.value == 'manual' && !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>',
dataTitle: 'Project Path',
dataContainer: 'body',
dataPlacement: 'right'
},
scm_url: {
label: 'SCM URL',
type: 'text',
ngShow: "scm_type && scm_type.value !== 'manual'",
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> When using SSH protocol for GitHub or Bitbucket, enter an SSH key only, ' +
'do not enter a username (other than git). Additionally, GitHub and Bitbucket do not support password authentication when using ' +
'SSH. GIT read only protocol (git://) does not use username or password information.',
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. ' +
'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 !== 'manual'",
addRequired: false,
editRequired: false
},
credential: {
label: 'SCM Credential',
type: 'lookup',
ngShow: "scm_type && scm_type.value !== 'manual'",
sourceModel: 'credential',
sourceField: 'name',
ngClick: 'lookUpCredential()',
addRequired: false,
editRequired: false
},
checkbox_group: {
label: 'SCM Update Options',
type: 'checkbox_group',
ngShow: "scm_type && scm_type.value !== 'manual'",
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'
}]
},
scm_update_cache_timeout: {
label: 'Cache Timeout<span class=\"small-text\"> (seconds)</span>',
id: 'scm-cache-timeout',
type: 'number',
integer: true,
min: 0,
ngShow: "scm_update_on_launch",
spinner: true,
"default": '0',
addRequired: false,
editRequired: false,
awPopOver: '<p>Time in seconds to consider a project to be current. During job runs and callbacks the task system will ' +
'evaluate the timestamp of the latest project update. If it is older than Cache Timeout, it is not considered current, ' +
'and a new project update will be performed.</p>',
dataTitle: 'Cache Timeout',
dataPlacement: 'right',
dataContainer: "body"
}
},
buttons: {
save: {
ngClick: 'formSave()',
ngDisabled: true
},
cancel: {
ngClick: 'formCancel()'
}
},
related: {
organizations: {
type: 'collection',
title: 'Organizations',
iterator: 'organization',
index: false,
open: false,
actions: {
add: {
ngClick: "add('organizations')",
label: 'Add',
awToolTip: 'Add an organization',
actionClass: 'btn List-buttonSubmit',
buttonContent: '&#43; ADD'
}
},
fields: {
name: {
key: true,
label: 'Name'
},
description: {
label: 'Description'
}
},
fieldActions: {
edit: {
label: 'Edit',
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, 'organization')",
icon: 'icon-trash',
"class": 'btn-danger',
awToolTip: 'Delete the organization'
}
}
},
schedules: {
type: 'collection',
title: 'Schedules',
iterator: 'schedule',
index: false,
open: false,
actions: {
refresh: {
mode: 'all',
awToolTip: "Refresh the page",
ngClick: "refreshSchedules()",
actionClass: 'btn List-buttonDefault',
buttonContent: 'REFRESH',
ngHide: 'scheduleLoading == false && schedule_active_search == false && schedule_total_rows < 1'
},
add: {
mode: 'all',
ngClick: 'addSchedule()',
awToolTip: 'Add a new schedule',
actionClass: 'btn List-buttonSubmit',
buttonContent: '&#43; ADD'
}
},
fields: {
name: {
key: true,
label: 'Name',
ngClick: "editSchedule(schedule.id)",
columnClass: "col-md-3 col-sm-3 col-xs-3"
},
dtstart: {
label: 'First Run',
filter: "longDate",
searchable: false,
columnClass: "col-md-2 col-sm-3 hidden-xs"
},
next_run: {
label: 'Next Run',
filter: "longDate",
searchable: false,
columnClass: "col-md-2 col-sm-3 col-xs-3"
},
dtend: {
label: 'Final Run',
filter: "longDate",
searchable: false,
columnClass: "col-md-2 col-sm-3 hidden-xs"
}
},
fieldActions: {
"play": {
mode: "all",
ngClick: "toggleSchedule($event, schedule.id)",
awToolTip: "{{ schedule.play_tip }}",
dataTipWatch: "schedule.play_tip",
iconClass: "{{ 'fa icon-schedule-enabled-' + schedule.enabled }}",
dataPlacement: "top"
},
edit: {
label: 'Edit',
ngClick: "editSchedule(schedule.id)",
icon: 'icon-edit',
awToolTip: 'Edit schedule',
dataPlacement: 'top'
},
"delete": {
label: 'Delete',
ngClick: "deleteSchedule(schedule.id)",
icon: 'icon-trash',
awToolTip: 'Delete schedule',
dataPlacement: 'top'
}
}
}
},
relatedSets: function(urls) {
return {
organizations: {
iterator: 'organization',
url: urls.organizations
},
schedules: {
iterator: 'schedule',
url: urls.schedules
}
};
}
})
.factory('ProjectsForm', ['ProjectsFormObject', 'SchedulesList', function(ProjectsFormObject, ScheduleList) {
return function() {
var itm;
for (itm in ProjectsFormObject.related) {
if (ProjectsFormObject.related[itm].include === "SchedulesList") {
ProjectsFormObject.related[itm] = ScheduleList;
ProjectsFormObject.related[itm].generateList = true; // tell form generator to call list generator and inject a list
}
}
return ProjectsFormObject;
};
}]);