Merge pull request #6724 from mabashian/3201-labels-pagination

Fixed GET labels pagination on job templates and workflows
This commit is contained in:
Michael Abashian 2017-06-27 12:14:48 -04:00 committed by GitHub
commit 70d856b35e
10 changed files with 576 additions and 518 deletions

View File

@ -23,6 +23,7 @@ import apiLoader from './api-loader';
import variables from './variables/main';
import parse from './parse/main';
import loadconfig from './load-config/main';
import nextpage from './next-page/main';
import Modal from './Modal';
import moment from './moment/main';
import config from './config/main';
@ -50,6 +51,7 @@ angular.module('shared', [listGenerator.name,
variables.name,
parse.name,
loadconfig.name,
nextpage.name,
Modal.name,
moment.name,
config.name,

View File

@ -0,0 +1,5 @@
import NextPage from './next-page.factory';
export default
angular.module('nextpage', [])
.factory('NextPage', NextPage);

View File

@ -0,0 +1,28 @@
export default
function NextPage(Rest, $q) {
return function(params) {
let getNext = function(getNextParams){
Rest.setUrl(getNextParams.url);
return Rest.get()
.then(function (res) {
if (res.data.next) {
return getNext({
url: res.data.next,
arrayOfValues: getNextParams.arrayOfValues.concat(res.data.results)
});
} else {
return $q.resolve(getNextParams.arrayOfValues.concat(res.data.results));
}
})
.catch(function(response) {
return $q.reject( response );
});
};
return getNext(params);
};
}
NextPage.$inject = ['Rest', '$q'];

View File

@ -8,25 +8,16 @@
[ '$filter', '$scope',
'$stateParams', 'JobTemplateForm', 'GenerateForm', 'Rest', 'Alert',
'ProcessErrors', 'GetBasePath', 'md5Setup', 'ParseTypeChange', 'Wait',
'Empty', 'ToJSON', 'CallbackHelpInit', 'GetChoices', '$state',
'CreateSelect2', '$q', 'i18n', 'Inventory', 'Project', 'InstanceGroupsService', 'MultiCredentialService',
'Empty', 'ToJSON', 'CallbackHelpInit', 'GetChoices', '$state', 'availableLabels',
'CreateSelect2', '$q', 'i18n', 'Inventory', 'Project', 'InstanceGroupsService', 'MultiCredentialService',
function(
$filter, $scope,
$stateParams, JobTemplateForm, GenerateForm, Rest, Alert,
ProcessErrors, GetBasePath, md5Setup, ParseTypeChange, Wait,
Empty, ToJSON, CallbackHelpInit, GetChoices,
$state, CreateSelect2, $q, i18n, Inventory, Project, InstanceGroupsService, MultiCredentialService
$state, availableLabels, CreateSelect2, $q, i18n, Inventory, Project, InstanceGroupsService, MultiCredentialService
) {
Rest.setUrl(GetBasePath('job_templates'));
Rest.options()
.success(function(data) {
if (!data.actions.POST) {
$state.go("^");
Alert(i18n._('Permission Error'), i18n._('You do not have permission to add a job template.'), 'alert-info');
}
});
// Inject dynamic view
let defaultUrl = GetBasePath('job_templates'),
form = JobTemplateForm(),
@ -61,7 +52,6 @@
$scope[form.name + '_form'].$setDirty();
};
var selectCount = 0;
if ($scope.removeChoicesReady) {
@ -118,20 +108,9 @@
callback: 'choicesReadyVerbosity'
});
Rest.setUrl(GetBasePath('labels'));
Rest.get()
.success(function (data) {
$scope.labelOptions = data.results
.map((i) => ({label: i.name, value: i.id}));
$scope.$emit("choicesReadyVerbosity");
})
.error(function (data, status) {
ProcessErrors($scope, data, status, form, {
hdr: 'Error!',
msg: 'Failed to get labels. GET returned ' +
'status: ' + status
});
});
$scope.labelOptions = availableLabels
.map((i) => ({label: i.name, value: i.id}));
$scope.$emit("choicesReadyVerbosity");
function sync_playbook_select2() {
CreateSelect2({
@ -236,131 +215,6 @@
$state.go('templates.editJobTemplate', {job_template_id: id}, {reload: true});
}
if ($scope.removeTemplateSaveSuccess) {
$scope.removeTemplateSaveSuccess();
}
$scope.removeTemplateSaveSuccess = $scope.$on('templateSaveSuccess', function(e, data) {
Wait('stop');
if (data.related &&
data.related.callback) {
Alert('Callback URL',
`Host callbacks are enabled for this template. The callback URL is:
<p style=\"padding: 10px 0;\">
<strong>
${$scope.callback_server_path}
${data.related.callback}
</strong>
</p>
<p>The host configuration key is:
<strong>
${$filter('sanitize')(data.host_config_key)}
</strong>
</p>`,
'alert-danger', saveCompleted, null, null,
null, true);
}
MultiCredentialService
.saveExtraCredentials({
creds: $scope.selectedCredentials.extra,
url: data.related.extra_credentials
});
var orgDefer = $q.defer();
var associationDefer = $q.defer();
Rest.setUrl(data.related.labels);
var currentLabels = Rest.get()
.then(function(data) {
return data.data.results
.map(val => val.id);
});
currentLabels.then(function (current) {
var labelsToAdd = ($scope.labels || [])
.map(val => val.value);
var labelsToDisassociate = current
.filter(val => labelsToAdd
.indexOf(val) === -1)
.map(val => ({id: val, disassociate: true}));
var labelsToAssociate = labelsToAdd
.filter(val => current
.indexOf(val) === -1)
.map(val => ({id: val, associate: true}));
var pass = labelsToDisassociate
.concat(labelsToAssociate);
associationDefer.resolve(pass);
});
Rest.setUrl(GetBasePath("organizations"));
Rest.get()
.success(function(data) {
orgDefer.resolve(data.results[0].id);
});
orgDefer.promise.then(function(orgId) {
var toPost = [];
$scope.newLabels = $scope.newLabels
.map(function(i, val) {
val.organization = orgId;
return val;
});
$scope.newLabels.each(function(i, val) {
toPost.push(val);
});
associationDefer.promise.then(function(arr) {
toPost = toPost
.concat(arr);
Rest.setUrl(data.related.labels);
var defers = [];
for (var i = 0; i < toPost.length; i++) {
defers.push(Rest.post(toPost[i]));
}
$q.all(defers)
.then(function() {
$scope.addedItem = data.id;
if($scope.survey_questions &&
$scope.survey_questions.length > 0){
//once the job template information
// is saved we submit the survey
// info to the correct endpoint
var url = data.url+ 'survey_spec/';
Rest.setUrl(url);
Rest.post({ name: $scope.survey_name,
description: $scope.survey_description,
spec: $scope.survey_questions })
.success(function () {
Wait('stop');
})
.error(function (data,
status) {
ProcessErrors(
$scope,
data,
status,
form,
{
hdr: 'Error!',
msg: 'Failed to add new ' +
'survey. Post returned ' +
'status: ' +
status
});
});
}
saveCompleted(data.id);
});
});
});
});
// Save
$scope.formSave = function () {
var fld, data = {};
@ -443,7 +297,124 @@
Rest.setUrl(defaultUrl);
Rest.post(data)
.then(({data}) => {
$scope.$emit('templateSaveSuccess', data);
Wait('stop');
if (data.related && data.related.callback) {
Alert('Callback URL',
`Host callbacks are enabled for this template. The callback URL is:
<p style=\"padding: 10px 0;\">
<strong>
${$scope.callback_server_path}
${data.related.callback}
</strong>
</p>
<p>The host configuration key is:
<strong>
${$filter('sanitize')(data.host_config_key)}
</strong>
</p>`,
'alert-danger', saveCompleted, null, null,
null, true);
}
MultiCredentialService
.saveExtraCredentials({
creds: $scope.selectedCredentials.extra,
url: data.related.extra_credentials
});
var orgDefer = $q.defer();
var associationDefer = $q.defer();
Rest.setUrl(data.related.labels);
var currentLabels = Rest.get()
.then(function(data) {
return data.data.results
.map(val => val.id);
});
currentLabels.then(function (current) {
var labelsToAdd = ($scope.labels || [])
.map(val => val.value);
var labelsToDisassociate = current
.filter(val => labelsToAdd
.indexOf(val) === -1)
.map(val => ({id: val, disassociate: true}));
var labelsToAssociate = labelsToAdd
.filter(val => current
.indexOf(val) === -1)
.map(val => ({id: val, associate: true}));
var pass = labelsToDisassociate
.concat(labelsToAssociate);
associationDefer.resolve(pass);
});
Rest.setUrl(GetBasePath("organizations"));
Rest.get()
.success(function(data) {
orgDefer.resolve(data.results[0].id);
});
orgDefer.promise.then(function(orgId) {
var toPost = [];
$scope.newLabels = $scope.newLabels
.map(function(i, val) {
val.organization = orgId;
return val;
});
$scope.newLabels.each(function(i, val) {
toPost.push(val);
});
associationDefer.promise.then(function(arr) {
toPost = toPost
.concat(arr);
Rest.setUrl(data.related.labels);
var defers = [];
for (var i = 0; i < toPost.length; i++) {
defers.push(Rest.post(toPost[i]));
}
$q.all(defers)
.then(function() {
$scope.addedItem = data.id;
if($scope.survey_questions &&
$scope.survey_questions.length > 0){
//once the job template information
// is saved we submit the survey
// info to the correct endpoint
var url = data.url+ 'survey_spec/';
Rest.setUrl(url);
Rest.post({ name: $scope.survey_name,
description: $scope.survey_description,
spec: $scope.survey_questions })
.success(function () {
Wait('stop');
})
.error(function (data,
status) {
ProcessErrors(
$scope,
data,
status,
form,
{
hdr: 'Error!',
msg: 'Failed to add new ' +
'survey. Post returned ' +
'status: ' +
status
});
});
}
saveCompleted(data.id);
});
});
});
const instance_group_url = data.related.instance_groups;
InstanceGroupsService.addInstanceGroups(instance_group_url, $scope.instance_groups)

View File

@ -14,17 +14,17 @@ export default
[ '$filter', '$scope', '$rootScope',
'$location', '$stateParams', 'JobTemplateForm', 'GenerateForm',
'Rest', 'Alert', 'ProcessErrors', 'GetBasePath', 'md5Setup',
'ParseTypeChange', 'Wait',
'ParseTypeChange', 'Wait', 'selectedLabels',
'Empty', 'Prompt', 'ToJSON', 'GetChoices', 'CallbackHelpInit',
'InitiatePlaybookRun' , 'initSurvey', '$state', 'CreateSelect2',
'ToggleNotification','$q', 'InstanceGroupsService', 'InstanceGroupsData', 'MultiCredentialService',
'ToggleNotification','$q', 'InstanceGroupsService', 'InstanceGroupsData', 'MultiCredentialService', 'availableLabels',
function(
$filter, $scope, $rootScope,
$location, $stateParams, JobTemplateForm, GenerateForm, Rest, Alert,
ProcessErrors, GetBasePath, md5Setup,
ParseTypeChange, Wait,
ParseTypeChange, Wait, selectedLabels,
Empty, Prompt, ToJSON, GetChoices, CallbackHelpInit, InitiatePlaybookRun, SurveyControllerInit, $state,
CreateSelect2, ToggleNotification, $q, InstanceGroupsService, InstanceGroupsData, MultiCredentialService
CreateSelect2, ToggleNotification, $q, InstanceGroupsService, InstanceGroupsData, MultiCredentialService, availableLabels
) {
$scope.$watch('job_template_obj.summary_fields.user_capabilities.edit', function(val) {
@ -39,7 +39,7 @@ export default
base = $location.path().replace(/^\//, '').split('/')[0],
master = {},
id = $stateParams.job_template_id,
checkSCMStatus, getPlaybooks, callback,
callback,
choicesCount = 0,
instance_group_url = defaultUrl + id + '/instance_groups';
@ -61,6 +61,88 @@ export default
id: id,
templateType: 'job_template'
});
$scope.$watch('project', function (newValue, oldValue) {
if (newValue !== oldValue) {
var url;
if ($scope.playbook) {
$scope.playbook_options = [$scope.playbook];
}
if (!Empty($scope.project)) {
let promises = [];
url = GetBasePath('projects') + $scope.project + '/playbooks/';
Wait('start');
Rest.setUrl(url);
promises.push(Rest.get()
.success(function (data) {
$scope.disablePlaybookBecausePermissionDenied = false;
$scope.playbook_options = [];
var playbookNotFound = true;
for (var i = 0; i < data.length; i++) {
$scope.playbook_options.push(data[i]);
if (data[i] === $scope.playbook) {
$scope.job_template_form.playbook.$setValidity('required', true);
playbookNotFound = false;
}
}
$scope.playbookNotFound = playbookNotFound;
sync_playbook_select2();
if ($scope.playbook) {
jobTemplateLoadFinished();
}
})
.error(function (ret,status_code) {
if (status_code === 403) {
/* user doesn't have access to see the project, no big deal. */
$scope.disablePlaybookBecausePermissionDenied = true;
} else {
Alert('Missing Playbooks', 'Unable to retrieve the list of playbooks for this project. Choose a different ' +
' project or make the playbooks available on the file system.', 'alert-info');
}
Wait('stop');
}));
Rest.setUrl(GetBasePath('projects') + $scope.project + '/');
promises.push(Rest.get()
.success(function (data) {
var msg;
switch (data.status) {
case 'failed':
msg = "<div>The Project selected has a status of \"failed\". You must run a successful update before you can select a playbook. You will not be able to save this Job Template without a valid playbook.";
break;
case 'never updated':
msg = "<div>The Project selected has a status of \"never updated\". You must run a successful update before you can select a playbook. You will not be able to save this Job Template without a valid playbook.";
break;
case 'missing':
msg = '<div>The selected project has a status of \"missing\". Please check the server and make sure ' +
' the directory exists and file permissions are set correctly.</div>';
break;
}
if (msg) {
Alert('Warning', msg, 'alert-info alert-info--noTextTransform', null, null, null, null, true);
}
})
.error(function (data, status) {
if (status === 403) {
/* User doesn't have read access to the project, no problem. */
} else {
ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to get project ' + $scope.project +
'. GET returned status: ' + status });
}
}));
$q.all(promises)
.then(function(){
Wait('stop');
});
}
}
});
// watch for changes to 'verbosity', ensure we keep our select2 in sync when it changes.
$scope.$watch('verbosity', sync_verbosity_select2);
}
callback = function() {
@ -82,51 +164,17 @@ export default
});
}
getPlaybooks = function (project) {
var url;
if ($scope.playbook) {
$scope.playbook_options = [$scope.playbook];
}
function jobTemplateLoadFinished(){
CreateSelect2({
element:'#job_template_job_type',
multiple: false
});
if (!Empty(project)) {
url = GetBasePath('projects') + project + '/playbooks/';
Wait('start');
Rest.setUrl(url);
Rest.get()
.success(function (data) {
$scope.disablePlaybookBecausePermissionDenied = false;
$scope.playbook_options = [];
var playbookNotFound = true;
for (var i = 0; i < data.length; i++) {
$scope.playbook_options.push(data[i]);
if (data[i] === $scope.playbook) {
$scope.job_template_form.playbook.$setValidity('required', true);
playbookNotFound = false;
}
}
$scope.playbookNotFound = playbookNotFound;
sync_playbook_select2();
if ($scope.playbook) {
$scope.$emit('jobTemplateLoadFinished');
} else {
Wait('stop');
}
})
.error(function (ret,status_code) {
if (status_code === 403) {
/* user doesn't have access to see the project, no big deal. */
$scope.disablePlaybookBecausePermissionDenied = true;
} else {
Alert('Missing Playbooks', 'Unable to retrieve the list of playbooks for this project. Choose a different ' +
' project or make the playbooks available on the file system.', 'alert-info');
}
Wait('stop');
});
}
else {
Wait('stop');
}
};
CreateSelect2({
element:'#playbook-select',
multiple: false
});
}
$scope.jobTypeChange = function() {
sync_playbook_select2();
@ -149,72 +197,6 @@ export default
});
};
// Detect and alert user to potential SCM status issues
checkSCMStatus = function () {
if (!Empty($scope.project)) {
Wait('start');
Rest.setUrl(GetBasePath('projects') + $scope.project + '/');
Rest.get()
.success(function (data) {
var msg;
switch (data.status) {
case 'failed':
msg = "<div>The Project selected has a status of \"failed\". You must run a successful update before you can select a playbook. You will not be able to save this Job Template without a valid playbook.";
break;
case 'never updated':
msg = "<div>The Project selected has a status of \"never updated\". You must run a successful update before you can select a playbook. You will not be able to save this Job Template without a valid playbook.";
break;
case 'missing':
msg = '<div>The selected project has a status of \"missing\". Please check the server and make sure ' +
' the directory exists and file permissions are set correctly.</div>';
break;
}
Wait('stop');
if (msg) {
Alert('Warning', msg, 'alert-info alert-info--noTextTransform', null, null, null, null, true);
}
})
.error(function (data, status) {
if (status === 403) {
/* User doesn't have read access to the project, no problem. */
} else {
ProcessErrors($scope, data, status, form, { hdr: 'Error!', msg: 'Failed to get project ' + $scope.project +
'. GET returned status: ' + status });
}
});
}
};
// Register a watcher on project_name. Refresh the playbook list on change.
if ($scope.watchProjectUnregister) {
$scope.watchProjectUnregister();
}
$scope.watchProjectUnregister = $scope.$watch('project', function (newValue, oldValue) {
if (newValue !== oldValue) {
getPlaybooks($scope.project);
checkSCMStatus();
}
});
// watch for changes to 'verbosity', ensure we keep our select2 in sync when it changes.
$scope.$watch('verbosity', sync_verbosity_select2);
if ($scope.removeJobTemplateLoadFinished) {
$scope.removeJobTemplateLoadFinished();
}
$scope.removeJobTemplateLoadFinished = $scope.$on('jobTemplateLoadFinished', function () {
CreateSelect2({
element:'#job_template_job_type',
multiple: false
});
CreateSelect2({
element:'#playbook-select',
multiple: false
});
});
// Retrieve each related set and populate the playbook list
if ($scope.jobTemplateLoadedRemove) {
$scope.jobTemplateLoadedRemove();
@ -224,8 +206,6 @@ export default
master = masterObject;
getPlaybooks($scope.project);
dft = ($scope.host_config_key === "" || $scope.host_config_key === null) ? false : true;
md5Setup({
scope: $scope,
@ -236,7 +216,7 @@ export default
ParseTypeChange({ scope: $scope, field_id: 'job_template_variables', onChange: callback });
$scope.$emit('jobTemplateLoadFinished');
jobTemplateLoadFinished();
});
Wait('start');
@ -302,68 +282,21 @@ export default
callback: 'choicesReady'
});
Rest.setUrl(GetBasePath('labels'));
Wait("start");
Rest.get()
.success(function (data) {
$scope.labelOptions = data.results
.map((i) => ({label: i.name, value: i.id}));
$scope.labelOptions = availableLabels
.map((i) => ({label: i.name, value: i.id}));
var seeMoreResolve = $q.defer();
var opts = selectedLabels
.map(i => ({id: i.id + "",
test: i.name}));
var getNext = function(data, arr, resolve) {
Rest.setUrl(data.next);
Rest.get()
.success(function (data) {
if (data.next) {
getNext(data, arr.concat(data.results), resolve);
} else {
resolve.resolve(arr.concat(data.results));
}
});
};
if($state.params.job_template_id !== "null"){
Rest.setUrl(defaultUrl + $state.params.job_template_id +
"/labels");
Rest.get()
.success(function(data) {
if (data.next) {
getNext(data, data.results, seeMoreResolve);
} else {
seeMoreResolve.resolve(data.results);
}
CreateSelect2({
element:'#job_template_labels',
multiple: true,
addNew: true,
opts: opts
});
seeMoreResolve.promise.then(function (labels) {
$scope.$emit("choicesReady");
var opts = labels
.map(i => ({id: i.id + "",
test: i.name}));
CreateSelect2({
element:'#job_template_labels',
multiple: true,
addNew: true,
opts: opts
});
Wait("stop");
});
}).error(function(){
// job template id is null in this case
$scope.$emit("choicesReady");
});
}
else {
// job template doesn't exist
$scope.$emit("choicesReady");
}
})
.error(function (data, status) {
ProcessErrors($scope, data, status, form, {
hdr: 'Error!',
msg: 'Failed to get labels. GET returned ' +
'status: ' + status
});
});
$scope.$emit("choicesReady");
function saveCompleted() {
$state.go($state.current, {}, {reload: true});

View File

@ -77,7 +77,36 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplates.
});
});
}
}]
}],
availableLabels: ['ProcessErrors', 'TemplatesService',
function(ProcessErrors, TemplatesService) {
return TemplatesService.getAllLabelOptions()
.then(function(labels){
return labels;
}).catch(function(response){
ProcessErrors(null, response.data, response.status, null, {
hdr: 'Error!',
msg: 'Failed to get labels. GET returned status: ' +
response.status
});
});
}],
checkPermissions: ['Rest', 'GetBasePath', 'TemplatesService', 'Alert', 'ProcessErrors', '$state',
function(Rest, GetBasePath, TemplatesService, Alert, ProcessErrors, $state) {
return TemplatesService.getJobTemplateOptions()
.then(function(data) {
if (!data.actions.POST) {
$state.go("^");
Alert('Permission Error', 'You do not have permission to add a job template.', 'alert-info');
}
}).catch(function(response){
ProcessErrors(null, response.data, response.status, null, {
hdr: 'Error!',
msg: 'Failed to get job template options. OPTIONS returned status: ' +
response.status
});
});
}]
}
}
});
@ -117,6 +146,32 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplates.
'status: ' + status
});
});
}],
availableLabels: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', 'TemplatesService',
function(Rest, $stateParams, GetBasePath, ProcessErrors, TemplatesService) {
return TemplatesService.getAllLabelOptions()
.then(function(labels){
return labels;
}).catch(function(response){
ProcessErrors(null, response.data, response.status, null, {
hdr: 'Error!',
msg: 'Failed to get labels. GET returned status: ' +
response.status
});
});
}],
selectedLabels: ['Rest', '$stateParams', 'GetBasePath', 'TemplatesService', 'ProcessErrors',
function(Rest, $stateParams, GetBasePath, TemplatesService, ProcessErrors) {
return TemplatesService.getAllJobTemplateLabels($stateParams.job_template_id)
.then(function(labels){
return labels;
}).catch(function(response){
ProcessErrors(null, response.data, response.status, null, {
hdr: 'Error!',
msg: 'Failed to get workflow job template labels. GET returned status: ' +
response.status
});
});
}]
}
}
@ -129,6 +184,39 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplates.
form: 'WorkflowForm',
controllers: {
add: 'WorkflowAdd'
},
resolve: {
add: {
availableLabels: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', 'TemplatesService',
function(Rest, $stateParams, GetBasePath, ProcessErrors, TemplatesService) {
return TemplatesService.getAllLabelOptions()
.then(function(labels){
return labels;
}).catch(function(response){
ProcessErrors(null, response.data, response.status, null, {
hdr: 'Error!',
msg: 'Failed to get labels. GET returned status: ' +
response.status
});
});
}],
checkPermissions: ['Rest', 'GetBasePath', 'TemplatesService', 'Alert', 'ProcessErrors', '$state',
function(Rest, GetBasePath, TemplatesService, Alert, ProcessErrors, $state) {
return TemplatesService.getWorkflowJobTemplateOptions()
.then(function(data) {
if (!data.actions.POST) {
$state.go("^");
Alert('Permission Error', 'You do not have permission to add a workflow job template.', 'alert-info');
}
}).catch(function(response){
ProcessErrors(null, response.data, response.status, null, {
hdr: 'Error!',
msg: 'Failed to get workflow job template options. OPTIONS returned status: ' +
response.status
});
});
}]
}
}
});
@ -144,6 +232,49 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplates.
activityStream: true,
activityStreamTarget: 'workflow_job_template',
activityStreamId: 'workflow_job_template_id'
},
resolve: {
edit: {
availableLabels: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', 'TemplatesService',
function(Rest, $stateParams, GetBasePath, ProcessErrors, TemplatesService) {
return TemplatesService.getAllLabelOptions()
.then(function(labels){
return labels;
}).catch(function(response){
ProcessErrors(null, response.data, response.status, null, {
hdr: 'Error!',
msg: 'Failed to get labels. GET returned status: ' +
response.status
});
});
}],
selectedLabels: ['Rest', '$stateParams', 'GetBasePath', 'TemplatesService', 'ProcessErrors',
function(Rest, $stateParams, GetBasePath, TemplatesService, ProcessErrors) {
return TemplatesService.getAllWorkflowJobTemplateLabels($stateParams.workflow_job_template_id)
.then(function(labels){
return labels;
}).catch(function(response){
ProcessErrors(null, response.data, response.status, null, {
hdr: 'Error!',
msg: 'Failed to get workflow job template labels. GET returned status: ' +
response.status
});
});
}],
workflowJobTemplateData: ['$stateParams', 'TemplatesService', 'ProcessErrors',
function($stateParams, TemplatesService, ProcessErrors) {
return TemplatesService.getWorkflowJobTemplate($stateParams.workflow_job_template_id)
.then(function(res) {
return res.data;
}).catch(function(response){
ProcessErrors(null, response.data, response.status, null, {
hdr: 'Error!',
msg: 'Failed to get workflow job template. GET returned status: ' +
response.status
});
});
}]
}
}
});

View File

@ -4,7 +4,7 @@
* All Rights Reserved
*************************************************/
export default ['Rest', 'GetBasePath', '$q', function(Rest, GetBasePath, $q){
export default ['Rest', 'GetBasePath', '$q', 'NextPage', function(Rest, GetBasePath, $q, NextPage){
return {
deleteJobTemplate: function(id){
var url = GetBasePath('job_templates');
@ -34,23 +34,69 @@ export default ['Rest', 'GetBasePath', '$q', function(Rest, GetBasePath, $q){
Rest.setUrl(url);
return Rest.post(data);
},
getLabelOptions: function(){
var url = GetBasePath('labels');
var deferred = $q.defer();
Rest.setUrl(url);
Rest.get()
.success(function(data) {
// Turn the labels into something consumable
var labels = data.results.map((i) => ({label: i.name, value: i.id}));
deferred.resolve(labels);
}).error(function(msg, code) {
deferred.reject(msg, code);
});
return deferred.promise;
getAllLabelOptions: function() {
Rest.setUrl(GetBasePath('labels') + '?page_size=200');
return Rest.get()
.then(function(res) {
if (res.data.next) {
return NextPage({
url: res.data.next,
arrayOfValues: res.data.results
}).then(function(labels) {
return labels;
}).catch(function(response){
return $q.reject( response );
});
}
else {
return $q.resolve( res.data.results );
}
}).catch(function(response){
return $q.reject( response );
});
},
getAllJobTemplateLabels: function(id) {
Rest.setUrl(GetBasePath('job_templates') + id + "/labels?page_size=20");
return Rest.get()
.then(function(res) {
if (res.data.next) {
return NextPage({
url: res.data.next,
arrayOfValues: res.data.results
}).then(function(labels) {
return labels;
}).catch(function(response){
return $q.reject( response );
});
}
else {
return $q.resolve( res.data.results );
}
}).catch(function(response){
return $q.reject( response );
});
},
getAllWorkflowJobTemplateLabels: function(id) {
Rest.setUrl(GetBasePath('workflow_job_templates') + id + "/labels?page_size=200");
return Rest.get()
.then(function(res) {
if (res.data.next) {
return NextPage({
url: res.data.next,
arrayOfValues: res.data.results
}).then(function(labels) {
return labels;
}).catch(function(response){
return $q.reject( response );
});
}
else {
return $q.resolve( res.data.results );
}
}).catch(function(response){
return $q.reject( response );
});
},
getJobTemplate: function(id) {
var url = GetBasePath('job_templates');
@ -205,6 +251,36 @@ export default ['Rest', 'GetBasePath', '$q', function(Rest, GetBasePath, $q){
Rest.setUrl(url);
return Rest.post();
},
getWorkflowJobTemplateOptions: function() {
var deferred = $q.defer();
let url = GetBasePath('workflow_job_templates');
Rest.setUrl(url);
Rest.options()
.success(function(data) {
deferred.resolve(data);
}).error(function(msg, code) {
deferred.reject(msg, code);
});
return deferred.promise;
},
getJobTemplateOptions: function() {
var deferred = $q.defer();
let url = GetBasePath('job_templates');
Rest.setUrl(url);
Rest.options()
.success(function(data) {
deferred.resolve(data);
}).error(function(msg, code) {
deferred.reject(msg, code);
});
return deferred.promise;
}
};
}];

View File

@ -7,19 +7,10 @@
export default [
'$scope', 'WorkflowForm', 'GenerateForm', 'Alert', 'ProcessErrors',
'Wait', '$state', 'CreateSelect2', 'TemplatesService',
'ToJSON', 'ParseTypeChange', '$q', 'Rest', 'GetBasePath',
'ToJSON', 'ParseTypeChange', '$q', 'Rest', 'GetBasePath', 'availableLabels',
function($scope, WorkflowForm, GenerateForm, Alert, ProcessErrors,
Wait, $state, CreateSelect2, TemplatesService, ToJSON,
ParseTypeChange, $q, Rest, GetBasePath) {
Rest.setUrl(GetBasePath('workflow_job_templates'));
Rest.options()
.success(function(data) {
if (!data.actions.POST) {
$state.go("^");
Alert('Permission Error', 'You do not have permission to add a workflow job template.', 'alert-info');
}
});
ParseTypeChange, $q, Rest, GetBasePath, availableLabels) {
// Inject dynamic view
let form = WorkflowForm(),
@ -42,24 +33,14 @@ export default [
}
});
// Go out and grab the possible labels
TemplatesService.getLabelOptions()
.then(function(data){
$scope.labelOptions = data;
// select2-ify the labels input
CreateSelect2({
element:'#workflow_job_template_labels',
multiple: true,
addNew: true
});
}, function(error){
ProcessErrors($scope, error.data, error.status, form, {
hdr: 'Error!',
msg: 'Failed to get labels. GET returned ' +
'status: ' + error.status
});
});
$scope.labelOptions = availableLabels
.map((i) => ({label: i.name, value: i.id}));
CreateSelect2({
element:'#workflow_job_template_labels',
multiple: true,
addNew: true
});
}
$scope.formSave = function () {

View File

@ -9,12 +9,12 @@ export default [
'ProcessErrors', 'GetBasePath', '$q', 'ParseTypeChange',
'Wait', 'Empty', 'ToJSON', 'initSurvey', '$state', 'CreateSelect2',
'ParseVariableString', 'TemplatesService', 'Rest', 'ToggleNotification',
'OrgAdminLookup',
'OrgAdminLookup', 'availableLabels', 'selectedLabels', 'workflowJobTemplateData',
function($scope, $stateParams, WorkflowForm, GenerateForm, Alert,
ProcessErrors, GetBasePath, $q, ParseTypeChange, Wait, Empty,
ToJSON, SurveyControllerInit, $state, CreateSelect2, ParseVariableString,
TemplatesService, Rest, ToggleNotification, OrgAdminLookup) {
TemplatesService, Rest, ToggleNotification, OrgAdminLookup, availableLabels, selectedLabels, workflowJobTemplateData) {
$scope.$watch('workflow_job_template_obj.summary_fields.user_capabilities.edit', function(val) {
if (val === false) {
$scope.canAddWorkflowJobTemplate = false;
@ -46,125 +46,74 @@ export default [
templateType: 'workflow_job_template'
});
Rest.setUrl(GetBasePath('labels'));
Wait("start");
Rest.get()
.success(function (data) {
$scope.labelOptions = data.results
.map((i) => ({label: i.name, value: i.id}));
$scope.labelOptions = availableLabels
.map((i) => ({label: i.name, value: i.id}));
var seeMoreResolve = $q.defer();
var opts = selectedLabels
.map(i => ({id: i.id + "",
test: i.name}));
var getNext = function(data, arr, resolve) {
Rest.setUrl(data.next);
Rest.get()
.success(function (data) {
if (data.next) {
getNext(data, arr.concat(data.results), resolve);
} else {
resolve.resolve(arr.concat(data.results));
CreateSelect2({
element:'#workflow_job_template_labels',
multiple: true,
addNew: true,
opts: opts
});
$scope.workflow_job_template_obj = workflowJobTemplateData;
$scope.name = workflowJobTemplateData.name;
$scope.can_edit = workflowJobTemplateData.summary_fields.user_capabilities.edit;
let fld, i;
for (fld in form.fields) {
if (fld !== 'variables' && fld !== 'survey' && workflowJobTemplateData[fld] !== null && workflowJobTemplateData[fld] !== undefined) {
if (form.fields[fld].type === 'select') {
if ($scope[fld + '_options'] && $scope[fld + '_options'].length > 0) {
for (i = 0; i < $scope[fld + '_options'].length; i++) {
if (workflowJobTemplateData[fld] === $scope[fld + '_options'][i].value) {
$scope[fld] = $scope[fld + '_options'][i];
}
});
};
Rest.setUrl(GetBasePath('workflow_job_templates') + id +
"/labels");
Rest.get()
.success(function(data) {
if (data.next) {
getNext(data, data.results, seeMoreResolve);
} else {
seeMoreResolve.resolve(data.results);
}
seeMoreResolve.promise.then(function (labels) {
$scope.$emit("choicesReady");
var opts = labels
.map(i => ({id: i.id + "",
test: i.name}));
CreateSelect2({
element:'#workflow_job_template_labels',
multiple: true,
addNew: true,
opts: opts
});
Wait("stop");
});
}).error(function(){
// job template id is null in this case
$scope.$emit("choicesReady");
});
})
.error(function (data, status) {
ProcessErrors($scope, data, status, form, {
hdr: 'Error!',
msg: 'Failed to get labels. GET returned ' +
'status: ' + status
});
});
// Go out and GET the workflow job temlate data needed to populate the form
TemplatesService.getWorkflowJobTemplate(id)
.then(function(data){
let workflowJobTemplateData = data.data;
$scope.workflow_job_template_obj = workflowJobTemplateData;
$scope.name = workflowJobTemplateData.name;
$scope.can_edit = workflowJobTemplateData.summary_fields.user_capabilities.edit;
let fld, i;
for (fld in form.fields) {
if (fld !== 'variables' && fld !== 'survey' && workflowJobTemplateData[fld] !== null && workflowJobTemplateData[fld] !== undefined) {
if (form.fields[fld].type === 'select') {
if ($scope[fld + '_options'] && $scope[fld + '_options'].length > 0) {
for (i = 0; i < $scope[fld + '_options'].length; i++) {
if (workflowJobTemplateData[fld] === $scope[fld + '_options'][i].value) {
$scope[fld] = $scope[fld + '_options'][i];
}
}
} else {
$scope[fld] = workflowJobTemplateData[fld];
}
} else {
$scope[fld] = workflowJobTemplateData[fld];
if(!Empty(workflowJobTemplateData.summary_fields.survey)) {
$scope.survey_exists = true;
}
}
} else {
$scope[fld] = workflowJobTemplateData[fld];
if(!Empty(workflowJobTemplateData.summary_fields.survey)) {
$scope.survey_exists = true;
}
}
if (fld === 'variables') {
// Parse extra_vars, converting to YAML.
$scope.variables = ParseVariableString(workflowJobTemplateData.extra_vars);
ParseTypeChange({ scope: $scope, field_id: 'workflow_job_template_variables' });
}
if (form.fields[fld].type === 'lookup' && workflowJobTemplateData.summary_fields[form.fields[fld].sourceModel]) {
$scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
workflowJobTemplateData.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
}
}
if (fld === 'variables') {
// Parse extra_vars, converting to YAML.
$scope.variables = ParseVariableString(workflowJobTemplateData.extra_vars);
if(workflowJobTemplateData.organization) {
OrgAdminLookup.checkForAdminAccess({organization: workflowJobTemplateData.organization})
.then(function(canEditOrg){
$scope.canEditOrg = canEditOrg;
});
ParseTypeChange({ scope: $scope, field_id: 'workflow_job_template_variables' });
}
else {
$scope.canEditOrg = true;
if (form.fields[fld].type === 'lookup' && workflowJobTemplateData.summary_fields[form.fields[fld].sourceModel]) {
$scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
workflowJobTemplateData.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
}
}
Wait('stop');
$scope.url = workflowJobTemplateData.url;
$scope.survey_enabled = workflowJobTemplateData.survey_enabled;
$scope.includeWorkflowMaker = true;
}, function(error){
ProcessErrors($scope, error.data, error.status, form, {
hdr: 'Error!',
msg: 'Failed to get workflow job template. GET returned ' +
'status: ' + error.status
if(workflowJobTemplateData.organization) {
OrgAdminLookup.checkForAdminAccess({organization: workflowJobTemplateData.organization})
.then(function(canEditOrg){
$scope.canEditOrg = canEditOrg;
});
}
else {
$scope.canEditOrg = true;
}
$scope.url = workflowJobTemplateData.url;
$scope.survey_enabled = workflowJobTemplateData.survey_enabled;
$scope.includeWorkflowMaker = true;
$scope.$on('SurveySaved', function() {
Wait('stop');
$scope.survey_exists = true;
$scope.invalid_survey = false;
});
}
@ -337,15 +286,6 @@ export default [
});
};
if ($scope.removeSurveySaved) {
$scope.removeSurveySaved();
}
$scope.removeSurveySaved = $scope.$on('SurveySaved', function() {
Wait('stop');
$scope.survey_exists = true;
$scope.invalid_survey = false;
});
init();
}
];

View File

@ -9,14 +9,14 @@ describe('Controller: WorkflowAdd', () => {
GenerateForm,
TemplatesService,
q,
getLabelsDeferred,
createWorkflowJobTemplateDeferred,
httpBackend,
ProcessErrors,
CreateSelect2,
Wait,
ParseTypeChange,
ToJSON;
ToJSON,
availableLabels;
beforeEach(angular.mock.module('Tower'));
beforeEach(angular.mock.module('RestServices'));
@ -44,6 +44,11 @@ describe('Controller: WorkflowAdd', () => {
}
};
availableLabels = [{
name: "foo",
id: "1"
}];
Alert = jasmine.createSpy('Alert');
ProcessErrors = jasmine.createSpy('ProcessErrors');
CreateSelect2 = jasmine.createSpy('CreateSelect2');
@ -59,9 +64,10 @@ describe('Controller: WorkflowAdd', () => {
$provide.value('Wait', Wait);
$provide.value('ParseTypeChange', ParseTypeChange);
$provide.value('ToJSON', ToJSON);
$provide.value('availableLabels', availableLabels);
}));
beforeEach(angular.mock.inject( ($rootScope, $controller, $q, $httpBackend, _state_, _ConfigService_, _GetChoices_, _Alert_, _GenerateForm_, _ProcessErrors_, _CreateSelect2_, _Wait_, _ParseTypeChange_, _ToJSON_) => {
beforeEach(angular.mock.inject( ($rootScope, $controller, $q, $httpBackend, _state_, _ConfigService_, _GetChoices_, _Alert_, _GenerateForm_, _ProcessErrors_, _CreateSelect2_, _Wait_, _ParseTypeChange_, _ToJSON_, _availableLabels_) => {
scope = $rootScope.$new();
state = _state_;
q = $q;
@ -71,10 +77,10 @@ describe('Controller: WorkflowAdd', () => {
ProcessErrors = _ProcessErrors_;
CreateSelect2 = _CreateSelect2_;
Wait = _Wait_;
getLabelsDeferred = q.defer();
createWorkflowJobTemplateDeferred = q.defer();
ParseTypeChange = _ParseTypeChange_;
ToJSON = _ToJSON_;
availableLabels = _availableLabels_;
$httpBackend
.whenGET(/^\/api\/?$/)
@ -84,7 +90,6 @@ describe('Controller: WorkflowAdd', () => {
.whenGET(/\/static\/*/)
.respond(200, {});
TemplatesService.getLabelOptions = jasmine.createSpy('getLabelOptions').and.returnValue(getLabelsDeferred.promise);
TemplatesService.createWorkflowJobTemplate = jasmine.createSpy('createWorkflowJobTemplate').and.returnValue(createWorkflowJobTemplateDeferred.promise);
WorkflowAdd = $controller('WorkflowAdd', {
@ -97,21 +102,19 @@ describe('Controller: WorkflowAdd', () => {
CreateSelect2: CreateSelect2,
Wait: Wait,
ParseTypeChange: ParseTypeChange,
availableLabels: availableLabels,
ToJSON
});
}));
it('should get/set the label options and select2-ify the input', ()=>{
// Resolve TemplatesService.getLabelsForJobTemplate
getLabelsDeferred.resolve({
foo: "bar"
});
// We expect the digest cycle to fire off this call to /static/config.js so we go ahead and handle it
httpBackend.expectGET('/static/config.js').respond(200);
scope.$digest();
expect(scope.labelOptions).toEqual({
foo: "bar"
});
expect(scope.labelOptions).toEqual([{
label: "foo",
value: "1"
}]);
expect(CreateSelect2).toHaveBeenCalledWith({
element:'#workflow_job_template_labels',
multiple: true,
@ -119,18 +122,6 @@ describe('Controller: WorkflowAdd', () => {
});
});
it('should call ProcessErrors when getLabelsForJobTemplate returns a rejected promise', ()=>{
// Reject TemplatesService.getLabelsForJobTemplate
getLabelsDeferred.reject({
data: "mockedData",
status: 400
});
// We expect the digest cycle to fire off this call to /static/config.js so we go ahead and handle it
httpBackend.expectGET('/static/config.js').respond(200);
scope.$digest();
expect(ProcessErrors).toHaveBeenCalled();
});
describe('scope.formSave()', () => {
it('should call TemplatesService.createWorkflowJobTemplate', ()=>{