mirror of
https://github.com/ansible/awx.git
synced 2026-03-21 19:07:39 -02:30
Validate JT add and edit forms client-side
- Use form generator to add new `helperText` field to show the character limit next to the label in the UI - Style helper text like the checkbox text - Update both `add` and `edit` controllers to handle client-side validation for the `labels` field.
This commit is contained in:
@@ -171,6 +171,19 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.at-InputLabel--helpertext {
|
||||||
|
float: right;
|
||||||
|
font-size: 10px;
|
||||||
|
color: @default-stdout-txt;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-top: 2px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.at-InputLabel--error {
|
||||||
|
color: @at-color-error;
|
||||||
|
}
|
||||||
|
|
||||||
.at-InputLabel-required {
|
.at-InputLabel-required {
|
||||||
color: @at-color-error;
|
color: @at-color-error;
|
||||||
font-weight: @at-font-weight-heading;
|
font-weight: @at-font-weight-heading;
|
||||||
|
|||||||
@@ -684,6 +684,10 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
html += createCheckbox(options.checkbox);
|
html += createCheckbox(options.checkbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options && options.helpertext) {
|
||||||
|
html += createHelpertext(options.helpertext);
|
||||||
|
}
|
||||||
|
|
||||||
if (field.labelAction) {
|
if (field.labelAction) {
|
||||||
let action = field.labelAction;
|
let action = field.labelAction;
|
||||||
let href = action.href || "";
|
let href = action.href || "";
|
||||||
@@ -1041,6 +1045,17 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (field.helperText) {
|
||||||
|
labelOptions.helpertext = {
|
||||||
|
id: `${this.form.name}_${fld}_sub_text`,
|
||||||
|
ngShow: field.helperText.ngShow,
|
||||||
|
ngModel: field.helperText.variable,
|
||||||
|
ngClass: field.helperText.ngClass,
|
||||||
|
classCondition: field.helperText.classCondition,
|
||||||
|
text: field.helperText.text
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
html += label(labelOptions);
|
html += label(labelOptions);
|
||||||
|
|
||||||
html += "<div ";
|
html += "<div ";
|
||||||
@@ -2021,5 +2036,17 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat
|
|||||||
${options.text}
|
${options.text}
|
||||||
</label> `;
|
</label> `;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createHelpertext (options) {
|
||||||
|
let ngModel = options.ngModel ? `ng-model="${options.ngModel}"` : '';
|
||||||
|
let ngShow = options.ngShow ? `ng-show="${options.ngShow}"` : '';
|
||||||
|
let ngClass = options.ngClass ? options.ngClass : '';
|
||||||
|
let classCondition = options.classCondition ? options.classCondition : '';
|
||||||
|
|
||||||
|
return `
|
||||||
|
<label class="at-InputLabel--helpertext" ng-class="!${classCondition} ? '${ngClass}' : ''" ${ngShow} id="${options.id}" ${ngModel}>
|
||||||
|
${options.text}
|
||||||
|
</label> `;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -495,5 +495,51 @@
|
|||||||
$scope.formCancel = function () {
|
$scope.formCancel = function () {
|
||||||
$state.transitionTo('templates');
|
$state.transitionTo('templates');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let handleLabelCount = () => {
|
||||||
|
/**
|
||||||
|
* This block of code specifically handles the client-side validation of the `labels` field.
|
||||||
|
* Due to it's detached nature in relation to the other job template fields, we must
|
||||||
|
* validate this field client-side in order to avoid the edge case where a user can make a
|
||||||
|
* successful POST to the `job_templates` endpoint but however encounter a 200 error from
|
||||||
|
* the `labels` endpoint due to a character limit.
|
||||||
|
*
|
||||||
|
* We leverage two of select2's available events, `select` and `unselect`, to detect when the user
|
||||||
|
* has either added or removed a label. From there, we set a flag and do simple string length
|
||||||
|
* checks to make sure a label's chacacter count remains under 512. Otherwise, we disable the "Save" button
|
||||||
|
* by invalidating the field and inform the user of the error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
$scope.job_template_labels_isValid = true;
|
||||||
|
const maxCount = 512;
|
||||||
|
const jt_label_id = 'job_template_labels';
|
||||||
|
|
||||||
|
// Detect when a new label is added
|
||||||
|
$(`#${jt_label_id}`).on('select2:select', (e) => {
|
||||||
|
const { text } = e.params.data;
|
||||||
|
|
||||||
|
// If the character count of an added label is greater than 512, we set `labels` field as invalid
|
||||||
|
if (text.length > maxCount) {
|
||||||
|
$scope.job_template_form.labels.$setValidity(`${jt_label_id}`, false);
|
||||||
|
$scope.job_template_labels_isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Detect when a label is removed
|
||||||
|
$(`#${jt_label_id}`).on('select2:unselect', (e) => {
|
||||||
|
const maxCount = 512;
|
||||||
|
const { text } = e.params.data;
|
||||||
|
|
||||||
|
/* If the character count of a removed label is greater than 512 AND the field is currently marked
|
||||||
|
as invalid, we set it back to valid */
|
||||||
|
if (text.length > maxCount && $scope.job_template_form.labels.$error) {
|
||||||
|
$scope.job_template_form.labels.$setValidity(`${jt_label_id}`, true);
|
||||||
|
$scope.job_template_labels_isValid = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleLabelCount();
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -588,19 +588,6 @@ export default
|
|||||||
.then(function() {
|
.then(function() {
|
||||||
Wait('stop');
|
Wait('stop');
|
||||||
saveCompleted();
|
saveCompleted();
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
// Handle any potential errors
|
|
||||||
let { data, status, config } = err;
|
|
||||||
const { url } = config;
|
|
||||||
|
|
||||||
// Handle edge case for LABELS endpoint
|
|
||||||
const labelName = "labels";
|
|
||||||
if (url.match(labelName)) {
|
|
||||||
data = { [labelName]: [data['name'][0]] };
|
|
||||||
}
|
|
||||||
ProcessErrors($scope, data, status, form, { hdr: 'Error!',
|
|
||||||
msg: 'Failed to update job template. PUT returned status: ' + status });
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -717,5 +704,51 @@ export default
|
|||||||
$scope.formCancel = function () {
|
$scope.formCancel = function () {
|
||||||
$state.go('templates');
|
$state.go('templates');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let handleLabelCount = () => {
|
||||||
|
/**
|
||||||
|
* This block of code specifically handles the client-side validation of the `labels` field.
|
||||||
|
* Due to it's detached nature in relation to the other job template fields, we must
|
||||||
|
* validate this field client-side in order to avoid the edge case where a user can make a
|
||||||
|
* successful POST to the `job_templates` endpoint but however encounter a 200 error from
|
||||||
|
* the `labels` endpoint due to a character limit.
|
||||||
|
*
|
||||||
|
* We leverage two of select2's available events, `select` and `unselect`, to detect when the user
|
||||||
|
* has either added or removed a label. From there, we set a flag and do simple string length
|
||||||
|
* checks to make sure a label's chacacter count remains under 512. Otherwise, we disable the "Save" button
|
||||||
|
* by invalidating the field and inform the user of the error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
$scope.job_template_labels_isValid = true;
|
||||||
|
const maxCount = 512;
|
||||||
|
const jt_label_id = 'job_template_labels';
|
||||||
|
|
||||||
|
// Detect when a new label is added
|
||||||
|
$(`#${jt_label_id}`).on('select2:select', (e) => {
|
||||||
|
const { text } = e.params.data;
|
||||||
|
|
||||||
|
// If the character count of an added label is greater than 512, we set `labels` field as invalid
|
||||||
|
if (text.length > maxCount) {
|
||||||
|
$scope.job_template_form.labels.$setValidity(`${jt_label_id}`, false);
|
||||||
|
$scope.job_template_labels_isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Detect when a label is removed
|
||||||
|
$(`#${jt_label_id}`).on('select2:unselect', (e) => {
|
||||||
|
const maxCount = 512;
|
||||||
|
const { text } = e.params.data;
|
||||||
|
|
||||||
|
/* If the character count of a removed label is greater than 512 AND the field is currently marked
|
||||||
|
as invalid, we set it back to valid */
|
||||||
|
if (text.length > maxCount && $scope.job_template_form.labels.$error) {
|
||||||
|
$scope.job_template_form.labels.$setValidity(`${jt_label_id}`, true);
|
||||||
|
$scope.job_template_labels_isValid = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleLabelCount();
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -229,6 +229,11 @@ function(NotificationsList, i18n) {
|
|||||||
dataPlacement: 'right',
|
dataPlacement: 'right',
|
||||||
awPopOver: "<p>" + i18n._("Optional labels that describe this job template, such as 'dev' or 'test'. Labels can be used to group and filter job templates and completed jobs.") + "</p>",
|
awPopOver: "<p>" + i18n._("Optional labels that describe this job template, such as 'dev' or 'test'. Labels can be used to group and filter job templates and completed jobs.") + "</p>",
|
||||||
dataContainer: 'body',
|
dataContainer: 'body',
|
||||||
|
helperText: {
|
||||||
|
classCondition: 'job_template_labels_isValid === true',
|
||||||
|
ngClass: 'at-InputLabel--error',
|
||||||
|
text: i18n._('Max 512 Char'),
|
||||||
|
},
|
||||||
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
|
ngDisabled: '!(job_template_obj.summary_fields.user_capabilities.edit || canAddJobTemplate)'
|
||||||
},
|
},
|
||||||
custom_virtualenv: {
|
custom_virtualenv: {
|
||||||
|
|||||||
Reference in New Issue
Block a user