1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-02 18:21:12 +03:00

job template labels ui implementation

This commit is contained in:
John Mitchell 2016-04-13 14:16:15 -04:00
parent d403c5fb3d
commit 9d9e2b254c
14 changed files with 591 additions and 126 deletions

View File

@ -38,6 +38,8 @@
.RoleList-deleteContainer {
border: 1px solid @default-second-border;
border-left-color: @default-bg;
background-color: @default-bg;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
padding: 0 5px;

View File

@ -189,6 +189,18 @@ export default
dataPlacement: "right",
dataContainer: "body"
},
labels: {
label: 'Labels',
type: 'select',
ngOptions: 'label.label for label in labelOptions track by label.value',
multiSelect: true,
addRequired: false,
editRequired: false,
dataTitle: 'Labels',
dataPlacement: 'right',
awPopOver: 'You can add labels to a job template to aid in filtering',
dataContainer: 'body'
},
variables: {
label: 'Extra Variables',
type: 'textarea',

View File

@ -11,14 +11,14 @@
'GetBasePath', 'InventoryList', 'CredentialList', 'ProjectList',
'LookUpInit', 'md5Setup', 'ParseTypeChange', 'Wait', 'Empty', 'ToJSON',
'CallbackHelpInit', 'initSurvey', 'Prompt', 'GetChoices', '$state',
'CreateSelect2',
'CreateSelect2', '$q',
function(
Refresh, $filter, $scope, $rootScope, $compile,
$location, $log, $stateParams, JobTemplateForm, GenerateForm, Rest, Alert,
ProcessErrors, ReturnToCaller, ClearScope, GetBasePath, InventoryList,
CredentialList, ProjectList, LookUpInit, md5Setup, ParseTypeChange, Wait,
Empty, ToJSON, CallbackHelpInit, SurveyControllerInit, Prompt, GetChoices,
$state, CreateSelect2
$state, CreateSelect2, $q
) {
ClearScope();
@ -113,7 +113,7 @@
}
$scope.removeChoicesReady = $scope.$on('choicesReadyVerbosity', function () {
selectCount++;
if (selectCount === 2) {
if (selectCount === 3) {
var verbosity;
// this sets the default options for the selects as specified by the controller.
for (verbosity in $scope.verbosity_options) {
@ -145,7 +145,11 @@
element:'#job_templates_job_type',
multiple: false
});
CreateSelect2({
element:'#job_templates_labels',
multiple: true,
addNew: true
});
CreateSelect2({
element:'#playbook-select',
multiple: false
@ -178,6 +182,21 @@
callback: 'choicesReadyVerbosity'
});
Rest.setUrl('api/v1/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
});
});
// Update playbook select whenever project value changes
selectPlaybook = function (oldValue, newValue) {
var url;
@ -265,12 +284,6 @@
}
};
// $scope.selectPlaybookUnregister = $scope.$watch('project_name', function (newval, oldval) {
// selectPlaybook(oldval, newval);
// checkSCMStatus(oldval, newval);
// });
// Register a watcher on project_name
if ($scope.selectPlaybookUnregister) {
$scope.selectPlaybookUnregister();
@ -311,14 +324,126 @@
}
$scope.removeTemplateSaveSuccess = $scope.$on('templateSaveSuccess', function(e, data) {
Wait('stop');
if (data.related && data.related.callback) {
Alert('Callback URL', '<p>Host callbacks are enabled for this template. The callback URL is:</p>'+
'<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-info', saveCompleted, null, null, null, true);
}
else {
saveCompleted();
if (data.related &&
data.related.callback) {
Alert('Callback URL',
`
<p>Host callbacks are enabled for this template. The callback URL is:</p>
<p style=\"padding: 10px 0;\">
<strong>
${$scope.callback_server_path}
${data.related.callback}
</string>
</p>
<p>The host configuration key is:
<strong>
${$filter('sanitize')(data.host_config_key)}
</string>
</p>
`,
'alert-info', saveCompleted, null, null,
null, true);
}
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;
Refresh({
scope: $scope,
set: 'job_templates',
iterator: 'job_template',
url: $scope.current_url
});
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();
});
});
});
});
// Save
@ -327,11 +452,13 @@
$scope.invalid_survey = false;
// users can't save a survey with a scan job
if($scope.job_type.value === "scan" && $scope.survey_enabled === true){
if($scope.job_type.value === "scan" &&
$scope.survey_enabled === true){
$scope.survey_enabled = false;
}
// Can't have a survey enabled without a survey
if($scope.survey_enabled === true && $scope.survey_exists!==true){
if($scope.survey_enabled === true &&
$scope.survey_exists!==true){
$scope.survey_enabled = false;
}
@ -341,70 +468,61 @@
try {
for (fld in form.fields) {
if (form.fields[fld].type === 'select' && fld !== 'playbook') {
if (form.fields[fld].type === 'select' &&
fld !== 'playbook') {
data[fld] = $scope[fld].value;
} else {
if (fld !== 'variables' && fld !== 'survey') {
if (fld !== 'variables' &&
fld !== 'survey') {
data[fld] = $scope[fld];
}
}
}
data.extra_vars = ToJSON($scope.parseType, $scope.variables, true);
if(data.job_type === 'scan' && $scope.default_scan === true){
data.extra_vars = ToJSON($scope.parseType,
$scope.variables, true);
if(data.job_type === 'scan' &&
$scope.default_scan === true){
data.project = "";
data.playbook = "";
}
// We only want to set the survey_enabled flag to true for this job template if a survey exists
// and it's been enabled. By default, survey_enabled is explicitly set to true but if no survey
// is created then we don't want it enabled.
data.survey_enabled = ($scope.survey_enabled && $scope.survey_exists) ? $scope.survey_enabled : false;
// We only want to set the survey_enabled flag to
// true for this job template if a survey exists
// and it's been enabled. By default,
// survey_enabled is explicitly set to true but
// if no survey is created then we don't want
// it enabled.
data.survey_enabled = ($scope.survey_enabled &&
$scope.survey_exists) ? $scope.survey_enabled : false;
$scope.newLabels = $("#job_templates_labels > option")
.filter("[data-select2-tag=true]")
.map((i, val) => ({name: $(val).text()}));
Rest.setUrl(defaultUrl);
Rest.post(data)
.success(function(data) {
$scope.$emit('templateSaveSuccess', data);
$scope.addedItem = data.id;
Refresh({
scope: $scope,
set: 'job_templates',
iterator: 'job_template',
url: $scope.current_url
});
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 });
});
}
$scope.$emit('templateSaveSuccess',
data);
})
.error(function (data, status) {
ProcessErrors($scope, data, status, form, { hdr: 'Error!',
msg: 'Failed to add new job template. POST returned status: ' + status
});
ProcessErrors($scope, data, status, form,
{
hdr: 'Error!',
msg: 'Failed to add new job ' +
'template. POST returned status: ' +
status
});
});
} catch (err) {
Wait('stop');
Alert("Error", "Error parsing extra variables. Parser returned: " + err);
Alert("Error", "Error parsing extra variables. " +
"Parser returned: " + err);
}
};
$scope.formCancel = function () {
$state.transitionTo('jobTemplates');
};
}
];

View File

@ -21,7 +21,7 @@ export default
'SchedulesControllerInit', 'JobsControllerInit', 'JobsListUpdate',
'GetChoices', 'SchedulesListInit', 'SchedulesList', 'CallbackHelpInit',
'PlaybookRun' , 'initSurvey', '$state', 'CreateSelect2',
'ToggleNotification', 'NotificationsListInit',
'ToggleNotification', 'NotificationsListInit', '$q',
function(
$filter, $scope, $rootScope, $compile,
$location, $log, $stateParams, JobTemplateForm, GenerateForm, Rest, Alert,
@ -31,7 +31,7 @@ export default
Empty, Prompt, ParseVariableString, ToJSON, SchedulesControllerInit,
JobsControllerInit, JobsListUpdate, GetChoices, SchedulesListInit,
SchedulesList, CallbackHelpInit, PlaybookRun, SurveyControllerInit, $state,
CreateSelect2, ToggleNotification, NotificationsListInit
CreateSelect2, ToggleNotification, NotificationsListInit, $q
) {
ClearScope();
@ -232,11 +232,6 @@ export default
multiple: false
});
CreateSelect2({
element:'#job_templates_verbosity',
multiple: false
});
for (var set in relatedSets) {
$scope.search(relatedSets[set].iterator);
}
@ -353,7 +348,7 @@ export default
}
$scope.removeChoicesReady = $scope.$on('choicesReady', function() {
choicesCount++;
if (choicesCount === 4) {
if (choicesCount === 5) {
$scope.$emit('LoadJobs');
}
});
@ -392,6 +387,41 @@ export default
callback: 'choicesReady'
});
Rest.setUrl('api/v1/labels');
Wait("start");
Rest.get()
.success(function (data) {
$scope.labelOptions = data.results
.map((i) => ({label: i.name, value: i.id}));
$scope.$emit("choicesReady");
Rest.setUrl(defaultUrl + $state.params.template_id +
"/labels");
Rest.get()
.success(function(data) {
var opts = data.results
.map(i => ({id: i.id + "",
test: i.name}));
CreateSelect2({
element:'#job_templates_labels',
multiple: true,
addNew: true,
opts: opts
});
Wait("stop");
});
CreateSelect2({
element:'#job_templates_verbosity',
multiple: false
});
})
.error(function (data, status) {
ProcessErrors($scope, data, status, form, {
hdr: 'Error!',
msg: 'Failed to get labels. GET returned ' +
'status: ' + status
});
});
function saveCompleted() {
$state.go('jobTemplates', null, {reload: true});
}
@ -401,34 +431,105 @@ export default
}
$scope.removeTemplateSaveSuccess = $scope.$on('templateSaveSuccess', function(e, data) {
Wait('stop');
if ($scope.allow_callbacks && ($scope.host_config_key !== master.host_config_key || $scope.callback_url !== master.callback_url)) {
if (data.related && data.related.callback) {
Alert('Callback URL', '<p>Host callbacks are enabled for this template. The callback URL is:</p>'+
'<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-info', saveCompleted, null, null, null, true);
}
else {
saveCompleted();
}
}
else {
saveCompleted();
if (data.related &&
data.related.callback) {
Alert('Callback URL',
`
<p>Host callbacks are enabled for this template. The callback URL is:</p>
<p style=\"padding: 10px 0;\">
<strong>
${$scope.callback_server_path}
${data.related.callback}
</string>
</p>
<p>The host configuration key is:
<strong>
${$filter('sanitize')(data.host_config_key)}
</string>
</p>
`,
'alert-info', saveCompleted, null, null,
null, true);
}
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() {
saveCompleted();
});
});
});
});
// Save changes to the parent
// Save
$scope.formSave = function () {
var fld, data = {};
$scope.invalid_survey = false;
// users can't save a survey with a scan job
if($scope.job_type.value === "scan" && $scope.survey_enabled === true){
if($scope.job_type.value === "scan" &&
$scope.survey_enabled === true){
$scope.survey_enabled = false;
}
// Can't have a survey enabled without a survey
if($scope.survey_enabled === true && $scope.survey_exists!==true){
if($scope.survey_enabled === true &&
$scope.survey_exists!==true){
$scope.survey_enabled = false;
}
@ -437,21 +538,38 @@ export default
Wait('start');
try {
// Make sure we have valid variable data
data.extra_vars = ToJSON($scope.parseType, $scope.variables, true);
if(data.extra_vars === undefined ){
throw 'undefined variables';
}
for (fld in form.fields) {
if (form.fields[fld].type === 'select' && fld !== 'playbook') {
if (form.fields[fld].type === 'select' &&
fld !== 'playbook') {
data[fld] = $scope[fld].value;
} else {
if (fld !== 'variables' && fld !== 'callback_url') {
if (fld !== 'variables' &&
fld !== 'survey') {
data[fld] = $scope[fld];
}
}
}
Rest.setUrl(defaultUrl + id + '/');
data.extra_vars = ToJSON($scope.parseType,
$scope.variables, true);
if(data.job_type === 'scan' &&
$scope.default_scan === true){
data.project = "";
data.playbook = "";
}
// We only want to set the survey_enabled flag to
// true for this job template if a survey exists
// and it's been enabled. By default,
// survey_enabled is explicitly set to true but
// if no survey is created then we don't want
// it enabled.
data.survey_enabled = ($scope.survey_enabled &&
$scope.survey_exists) ? $scope.survey_enabled : false;
$scope.newLabels = $("#job_templates_labels > option")
.filter("[data-select2-tag=true]")
.map((i, val) => ({name: $(val).text()}));
Rest.setUrl(defaultUrl + $state.params.template_id);
Rest.put(data)
.success(function (data) {
$scope.$emit('templateSaveSuccess', data);
@ -460,12 +578,11 @@ export default
ProcessErrors($scope, data, status, form, { hdr: 'Error!',
msg: 'Failed to update job template. PUT returned status: ' + status });
});
} catch (err) {
Wait('stop');
Alert("Error", "Error parsing extra variables. Parser returned: " + err);
Alert("Error", "Error parsing extra variables. " +
"Parser returned: " + err);
}
};
$scope.formCancel = function () {
@ -474,7 +591,7 @@ export default
var defaultUrl = GetBasePath('job_templates') + $state.params.template_id;
Rest.setUrl(defaultUrl);
Rest.destroy()
.success(function(res){
.success(function(){
$state.go('jobTemplates', null, {reload: true, notify:true});
})
.error(function(res, status){

View File

@ -0,0 +1,74 @@
/** @define LabelList */
@import "../shared/branding/colors.default.less";
.LabelList {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
}
.LabelList-tagContainer {
display: flex;
max-width: 100%;
}
.LabelList-tag {
border-radius: 5px;
padding: 2px 10px;
margin: 4px 0px;
border: 1px solid @default-second-border;
font-size: 12px;
color: @default-interface-txt;
text-transform: uppercase;
background-color: @default-bg;
margin-right: 5px;
max-width: 100%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.LabelList-tag--deletable {
margin-right: 0px;
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
border-right: 0;
max-wdith: ~"calc(100% - 23px)";
}
.LabelList-deleteContainer {
border: 1px solid @default-second-border;
border-left-color: @default-bg;
background-color: @default-bg;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
padding: 0 5px;
margin: 4px 0px;
margin-right: 5px;
align-items: center;
display: flex;
cursor: pointer;
}
.LabelList-tagDelete {
font-size: 13px;
color: @default-icon;
}
.LabelList-name {
flex: initial;
max-width: 100%;
}
.LabelList-tag--deletable > .LabelList-name {
max-width: ~"calc(100% - 23px)";
}
.LabelList-deleteContainer:hover, {
border-color: @default-err;
background-color: @default-err;
}
.LabelList-deleteContainer:hover > .LabelList-tagDelete {
color: @default-bg;
}

View File

@ -0,0 +1,45 @@
/* jshint unused: vars */
export default
[ 'templateUrl',
'Wait',
'Rest',
'GetBasePath',
'ProcessErrors',
'Prompt',
function(templateUrl, Wait, Rest, GetBasePath, ProcessErrors, Prompt) {
return {
restrict: 'E',
scope: false,
templateUrl: templateUrl('job-templates/labels/labelsList'),
link: function(scope, element, attrs) {
scope.labels = scope.
job_template.summary_fields.labels;
scope.deleteLabel = function(templateId, templateName, labelId, labelName) {
var action = function () {
$('#prompt-modal').modal('hide');
Wait('start');
var url = GetBasePath("job_templates") + templateId + "/labels/";
Rest.setUrl(url);
Rest.post({"disassociate": true, "id": labelId})
.success(function () {
Wait('stop');
scope.search("job_template");
})
.error(function (data, status) {
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Could not disacssociate label from JT. Call to ' + url + ' failed. DELETE returned status: ' + status });
});
};
Prompt({
hdr: 'Remove Label from ' + templateName,
body: '<div class="Prompt-bodyQuery">Confirm the removal of the <span class="Prompt-emphasis">' + labelName + '</span> label.</div>',
action: action,
actionText: 'REMOVE'
});
};
}
};
}
];

View File

@ -0,0 +1,10 @@
<div class="LabelList-tagContainer"
ng-repeat="label in labels">
<div class="LabelList-tag LabelList-tag--deletable">
<span class="LabelList-name">{{ label.name }}</span>
</div>
<div class="LabelList-deleteContainer"
ng-click="deleteLabel(job_template.id, job_template.name, label.id, label.name)">
<i class="fa fa-times LabelList-tagDelete"></i>
</div>
</div>

View File

@ -0,0 +1,11 @@
/*************************************************
* Copyright (c) 2015 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import labelsList from './labelsList.directive';
export default
angular.module('labels', [])
.directive('labelsList', labelsList);

View File

@ -11,9 +11,10 @@ import jobTemplatesList from './list/main';
import jobTemplatesAdd from './add/main';
import jobTemplatesEdit from './edit/main';
import jobTemplatesCopy from './copy/main';
import labels from './labels/main';
export default
angular.module('jobTemplates',
[surveyMaker.name, jobTemplatesList.name, jobTemplatesAdd.name,
jobTemplatesEdit.name, jobTemplatesCopy.name])
angular.module('jobTemplates',
[surveyMaker.name, jobTemplatesList.name, jobTemplatesAdd.name,
jobTemplatesEdit.name, jobTemplatesCopy.name, labels.name])
.service('deleteJobTemplate', deleteJobTemplate);

View File

@ -23,19 +23,28 @@ export default
name: {
key: true,
label: 'Name',
columnClass: 'col-lg-3 col-md-3 col-sm-4 col-xs-4'
columnClass: 'col-lg-2 col-md-2 col-sm-4 col-xs-9'
},
description: {
label: 'Description',
columnClass: 'col-lg-3 col-md-3 hidden-sm hidden-xs'
columnClass: 'col-lg-2 hidden-md hidden-sm hidden-xs'
},
smart_status: {
label: 'Activity',
columnClass: 'List-tableCell col-lg-4 col-md-4 col-sm-5 col-xs-5',
columnClass: 'List-tableCell col-lg-3 col-md-4 hidden-sm hidden-xs',
searchable: false,
nosort: true,
ngInclude: "'/static/partials/job-template-smart-status.html'",
type: 'template'
},
labels: {
label: 'Labels',
type: 'labels',
nosort: true,
columnClass: 'List-tableCell col-lg-3 col-md-3 hidden-sm hidden-xs',
searchType: 'related',
sourceModel: 'labels',
sourceField: 'name'
}
},
@ -52,7 +61,7 @@ export default
fieldActions: {
columnClass: 'col-lg-2 col-md-2 col-sm-3 col-xs-3',
columnClass: 'col-lg-2 col-md-3 col-sm-3 col-xs-3',
submit: {
label: 'Launch',

View File

@ -196,6 +196,8 @@
.TagSearch-deleteContainer {
border: 1px solid @default-second-border;
border-left-color: @default-bg;
background-color: @default-bg;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
padding: 0 5px;

View File

@ -3,9 +3,13 @@ export default ['Rest', '$q', 'GetBasePath', 'Wait', 'ProcessErrors', function(R
// parse the field config object to return
// one of the searchTypes (for the left dropdown)
this.buildType = function (field, key, id) {
var obj = {};
// build the value (key)
var value;
if (typeof(field.key) === String) {
if (field.sourceModel && field.sourceField) {
value = field.sourceModel + '__' + field.sourceField;
obj.related = true;
} else if (typeof(field.key) === String) {
value = field.key;
} else {
value = key;
@ -27,23 +31,19 @@ export default ['Rest', '$q', 'GetBasePath', 'Wait', 'ProcessErrors', function(R
type = 'text';
}
obj.id = id;
obj.value = value;
obj.label = label;
obj.type = type;
// return the built option
if (type === 'select') {
return {
id: id,
value: value,
label: label,
type: type,
typeOptions: typeOptions
};
} else {
return {
id: id,
value: value,
label: label,
type: type
};
obj.typeOptions = typeOptions;
}
return obj;
};
// given the fields that are searchable,
@ -116,6 +116,45 @@ export default ['Rest', '$q', 'GetBasePath', 'Wait', 'ProcessErrors', function(R
// returns the url with filter params
this.updateFilteredUrl = function(basePath, tags, pageSize) {
// remove the chain directive from all the urls that might have
// been added previously
tags = (tags || []).map(function(val) {
if (val.url.indexOf("chain__") !== -1) {
val.url = val.url.substring(("chain__").length);
}
return val;
});
// separate those tags with the related: true attribute
var separateRelated = _.partition(tags, function(i) {
return i.related;
});
var relatedTags = separateRelated[0];
var nonRelatedTags = separateRelated[1];
if (relatedTags.length > 1) {
// separate query params that need the change directive
// but have different keys
var chainGroups = _.groupBy(relatedTags, function(i) {
return i.value;
});
// iterate over those groups and add the "chain__" to the
// beginning of all but the first of each url
relatedTags = _.flatten(_.map(chainGroups, function(group) {
return group.map(function(val, i) {
if (i !== 0) {
val.url = "chain__" + val.url;
}
return val;
});
}));
// combine the related and non related tags after chainifying
tags = relatedTags.concat(nonRelatedTags);
}
return basePath + "?" +
(tags || []).map(function (t) {
return t.url;

View File

@ -616,7 +616,8 @@ angular.module('Utilities', ['RestServices', 'Utilities', 'sanitizeFilter'])
options = params.opts,
multiple = (params.multiple!==undefined) ? params.multiple : true,
placeholder = params.placeholder,
customDropdownAdapter = (params.customDropdownAdapter!==undefined) ? params.customDropdownAdapter : true;
customDropdownAdapter = (params.customDropdownAdapter!==undefined) ? params.customDropdownAdapter : true,
addNew = params.addNew;
$.fn.select2.amd.require([
'select2/utils',
@ -624,11 +625,12 @@ angular.module('Utilities', ['RestServices', 'Utilities', 'sanitizeFilter'])
'select2/dropdown/search',
'select2/dropdown/attachContainer',
'select2/dropdown/closeOnSelect',
'select2/dropdown/minimumResultsForSearch'
], function (Utils, Dropdown, Search, AttachContainer, CloseOnSelect, MinimumResultsForSearch) {
'select2/dropdown/minimumResultsForSearch',
'select2/data/tokenizer'
], function (Utils, Dropdown, Search, AttachContainer, CloseOnSelect, MinimumResultsForSearch, Tokenizer) {
var CustomAdapter =
_.reduce([Search, AttachContainer, CloseOnSelect, MinimumResultsForSearch],
_.reduce([Search, AttachContainer, CloseOnSelect, MinimumResultsForSearch, Tokenizer],
function(Adapter, Decorator) {
return Utils.Decorate(Adapter, Decorator);
}, Dropdown);
@ -639,14 +641,20 @@ angular.module('Utilities', ['RestServices', 'Utilities', 'sanitizeFilter'])
containerCssClass: 'Form-dropDown',
width: '100%',
minimumResultsForSearch: Infinity,
}
};
// multiple-choice directive calls select2 but needs to do so without this custom adapter
// to allow the element to be draggable on survey preview.
if(customDropdownAdapter) {
if (customDropdownAdapter) {
config.dropdownAdapter = CustomAdapter;
}
if (addNew) {
$(element).prepend("<option></option>");
config.tags = true;
config.tokenSeparators = [];
}
$(element).select2(config);
if(options){
@ -884,7 +892,7 @@ angular.module('Utilities', ['RestServices', 'Utilities', 'sanitizeFilter'])
}
])
.factory('ParamPass', function() {
var savedData = undefined;
var savedData;
function set(data) {
savedData = data;
@ -899,5 +907,5 @@ angular.module('Utilities', ['RestServices', 'Utilities', 'sanitizeFilter'])
return {
set: set,
get: get
}
};
});

View File

@ -448,12 +448,29 @@ angular.module('GeneratorHelpers', [systemStatus.name])
options = params.options,
base = params.base,
field = list.fields[fld],
html = '';
html = '',
classList;
if (field.type !== undefined && field.type === 'DropDown') {
html = DropDown(params);
} else if (field.type === 'role') {
html += "<td class=\"List-tableCell\"><role-list class=\"RoleList\"></role-list></td>";
classList = (field.columnClass) ?
Attr(field, 'columnClass') : "";
html += `
<td ${classList}>
<role-list class=\"RoleList\">
</role-list>
</td>
`;
} else if (field.type === 'labels') {
classList = (field.columnClass) ?
Attr(field, 'columnClass') : "";
html += `
<td ${classList}>
<labels-list class=\"LabelList\">
</labels-list>
</td>
`;
} else if (field.type === 'badgeCount') {
html = BadgeCount(params);
} else if (field.type === 'badgeOnly') {