static/js/stage.js (355 lines of code) (raw):
$(function () {
function isStageAdded() {
let currentStageName = $('#stageName').val();
let stageNames = $('input[name="stageName"][data-mode="add"]').map(function () {
return $(this).val();
}).get();
return !!($.inArray(currentStageName, stageNames) !== -1);
}
$('.add-stage').click(function () {
let $stageAddedMsgEl = $('.invalid-feedback.stage-added-msg');
if (validateFields()) {
if (isStageAdded()) {
$stageAddedMsgEl.show();
return;
}
$stageAddedMsgEl.hide();
appendStage(collectStageData());
resetFields();
$('#stage-creation').modal('hide');
}
});
$('.confirm-edit-stage').click(function () {
function replaceOldValues(stageToEdit, stageData) {
stageToEdit.removeClass($('#stage-creation').attr('old-name'));
stageToEdit.find('.stage-name a').text(stageData.stageName);
stageToEdit.find('.edit-stage').attr('name', stageData.stageName);
stageToEdit.find('.remove-stage').attr('name', stageData.stageName);
stageToEdit.addClass(stageData.stageName);
stageToEdit.find('#stageNameForm').val(stageData.stageName);
stageToEdit.find('#stageDescForm').val(stageData.stageDesc).attr('name', stageData.stageName + '-stageDesc');
stageToEdit.find('#triggerTypeForm').val(stageData.triggerType).attr('name', stageData.stageName + '-triggerType');
stageToEdit.find('#jobProvisioningForm').val(stageData.jobProvisioning).attr('name', stageData.stageName + '-jobProvisioning');
stageToEdit.find('#pipelineLibraryNameForm').val(stageData.pipelineLibraryName);
stageToEdit.find('#pipelineLibraryBranchForm').val(stageData.pipelineLibraryBranch);
let $stageBlockEl = $('.stage-info.' + stageData.stageName);
$stageBlockEl.find('.qualityGateType, .stepName, .autotestsName, .branchName').remove();
$.each(stageData.qualityGates, function () {
let qualityGateTypeInputName = stageData.stageName + '-' + this.stepName + '-stageQualityGateType',
stepNameInputName = stageData.stageName + '-stageStepName',
autotestsInputName = stageData.stageName + '-' + this.stepName + '-stageAutotests',
branchInputName = stageData.stageName + '-' + this.stepName + '-stageBranch';
$('<input class="qualityGateType" type="hidden" name="' + qualityGateTypeInputName + '" value="' + this.qualityGateType + '">').appendTo($stageBlockEl);
$('<input class="stepName" type="hidden" name="' + stepNameInputName + '" value="' + this.stepName + '">').appendTo($stageBlockEl);
$('<input class="autotestsName" type="hidden" name="' + autotestsInputName + '" value="' + this.autotestName + '">').appendTo($stageBlockEl);
$('<input class="branchName" type="hidden" name="' + branchInputName + '" value="' + this.branchName + '">').appendTo($stageBlockEl)
});
}
let $stageAddedMsgEl = $('.invalid-feedback.stage-added-msg');
if (validateFields()) {
if (isStageAdded()) {
$stageAddedMsgEl.show();
return;
}
$stageAddedMsgEl.hide();
let stageData = collectStageData();
let $stageCreationModal = $('#stage-creation');
let stageToEdit = $('.stage-info.' + $stageCreationModal.attr('old-name'));
replaceOldValues(stageToEdit, stageData);
resetFields();
toggleAdding();
$stageCreationModal.modal('hide');
}
});
$('.stage-modal-close, .cancel-edit-stage').click(function () {
resetFields();
toggleAdding();
});
$('.tooltip-icon').tooltip();
$('#qualityGateType').change(function () {
let $autotestsEl = $(this).parents('.quality-gate-row').find('.autotest-block-el');
if (this.value === 'autotests') {
$autotestsEl.removeClass('hide-element');
} else {
$autotestsEl.addClass('hide-element');
}
});
$('.autotests-checkbox').change(function () {
if (this.checked) {
$('#qualityGateType').removeClass('non-valid-input');
$('.autotests-validation-msg').hide();
}
disableSelectElems();
});
$('.add-quality-gate-row').click(function () {
let $qualityGateTypeEl = $('.quality-gate-row:first').clone(true);
$qualityGateTypeEl.find('.qualityGateTypeLabel, .nameOfStepLabel, .autotestLabel, .branchLabel').remove();
$qualityGateTypeEl.find('#qualityGateType').val('manual');
$qualityGateTypeEl.find('.remove-quality-gate-type').removeClass('hide-element');
$qualityGateTypeEl.find('input.non-valid-input').removeClass('non-valid-input');
$qualityGateTypeEl.find('.invalid-feedback.step-name-validation-msg').hide();
$qualityGateTypeEl.find('.qualityGateType').val('manual');
$qualityGateTypeEl.find('.autotest-block-el').addClass('hide-element');
$qualityGateTypeEl.find('.nameOfStep').val('');
$qualityGateTypeEl.insertBefore($('.step-name-validation-msg'));
});
$('.remove-quality-gate-type').click(function () {
$(this).parents('.quality-gate-row').remove();
});
$('.autotest-projects').change(function () {
let selectedAutotest = $(this).val();
$.each($(this).parents('.quality-gate-row').find('.autotest-branches'), function () {
$(this).data('selected-autotest') === selectedAutotest ? $(this).show() : $(this).hide();
})
});
$('.pipeline-library').change(function () {
let $branchEl = $(this).parents('.pipeline-library-row').find('.branch-block-el');
if (this.value === 'default') {
$branchEl.addClass('hide-element');
} else {
$branchEl.removeClass('hide-element');
}
let selectedPipelineLibrary = $(this).val();
$.each($(this).parents('.pipeline-library-row').find('.pipeline-library-branches'), function () {
$(this).data('selected-pipeline-library') === selectedPipelineLibrary ? $(this).show() : $(this).hide();
$(this).prop('selectedIndex', 0);
})
});
!function () {
$('.quality-gate-row .autotest-branches').hide();
$.each($('.quality-gate-row .autotest-projects'), function () {
$('select[data-selected-autotest="' + $(this).val() + '"]').show();
});
$.each($('.pipeline-library-row .pipeline-library-branches'), function () {
$('select[data-selected-pipeline-library="' + $(this).val() + '"]').show();
});
}();
});
function validateFields() {
return handleStageNameValidation() & handleStageDescriptionValidation() & handleStepNameValidation();
}
function appendStage(stageData) {
$('<div class="d-flex stage-info ' + stageData.stageName + '">\n' +
' <div class="form-group w-50 mb-2 stage-name">\n' +
'<a class="edit-stage" onclick="editStage(this.name)" name="' + stageData.stageName + '" href="#">\n' + stageData.stageName + '</a>\n' +
' </div>\n' +
' <div class="d-flex flex-column justify-content-end mb-2">\n' +
' <button type="button" onclick="removeStage(this.name)" class="delete remove-stage" name="' + stageData.stageName + '" data-toggle="modal" data-target="#exampleModal">\n' +
' <i class="icon-trashcan"></i>\n' +
' </button>\n' +
' </div>\n' +
'<input data-mode="add" id="stageNameForm" name="stageName" type="hidden" value="' + stageData.stageName + '">' +
'<input id="stageDescForm" name="' + stageData.stageName + '-stageDesc" type="hidden" value="' + stageData.stageDesc + '">' +
'<input id="triggerTypeForm" name="' + stageData.stageName + '-triggerType" type="hidden" value="' + stageData.triggerType + '">' +
'<input id="jobProvisioningForm" name="' + stageData.stageName + '-jobProvisioning" type="hidden" value="' + stageData.jobProvisioning + '">' +
'<input id="pipelineLibraryNameForm" name="' + stageData.stageName + '-pipelineLibraryName" type="hidden" value="' + stageData.pipelineLibraryName + '">' +
'<input id="pipelineLibraryBranchForm" name="' + stageData.stageName + '-pipelineLibraryBranch" type="hidden" value="' + stageData.pipelineLibraryBranch + '">' +
' </div>').appendTo($('.stages-list'));
let $stageBlockEl = $('.stage-info.' + stageData.stageName);
$.each(stageData.qualityGates, function () {
let qualityGateTypeInputName = stageData.stageName + '-' + this.stepName + '-stageQualityGateType',
stepNameInputName = stageData.stageName + '-stageStepName',
autotestsInputName = stageData.stageName + '-' + this.stepName + '-stageAutotests',
branchInputName = stageData.stageName + '-' + this.stepName + '-stageBranch';
$('<input class="qualityGateType" type="hidden" name="' + qualityGateTypeInputName + '" value="' + this.qualityGateType + '">').appendTo($stageBlockEl);
$('<input class="stepName" type="hidden" name="' + stepNameInputName + '" value="' + this.stepName + '">').appendTo($stageBlockEl);
$('<input class="autotestsName" type="hidden" name="' + autotestsInputName + '" value="' + this.autotestName + '">').appendTo($stageBlockEl);
$('<input class="branchName" type="hidden" name="' + branchInputName + '" value="' + this.branchName + '">').appendTo($stageBlockEl)
});
}
function resetFields() {
$('#qualityGateType option:first').prop('selected', true);
$('#triggerType option:first').prop('selected', true);
$('#stage-creation input[type="text"]').val("");
$('#pipeline-library option:first').prop('selected', true);
$('input.non-valid-input, select.non-valid-input').removeClass('non-valid-input');
$('div.invalid-feedback').hide();
let $qualityGateTypeElems = $('.quality-gate-row');
$qualityGateTypeElems.not(':first').remove();
$qualityGateTypeElems.find('.qualityGateType').val('manual');
$qualityGateTypeElems.find('.autotest-block-el').addClass('hide-element');
$('.branch-block-el').addClass('hide-element');
}
function removeStage(stageName) {
$('.stage-info.' + stageName).remove();
}
function editStage(stageName) {
toggleEditing();
let $stageCreationModal = $('#stage-creation');
$stageCreationModal.attr('old-name', stageName);
$stageCreationModal.modal('show');
$('#stageNameForm[value="' + stageName + '"]').attr('data-mode', 'edit');
fillFields(stageName);
disableSelectElems();
}
function fillFields(stageName) {
let $stageEl = $('.stage-info.' + stageName);
$('#stageName').val($stageEl.find('#stageNameForm').val());
$('#stageDesc').val($stageEl.find('#stageDescForm').val());
$("#triggerType").val($stageEl.find('#triggerTypeForm').val());
$("#jobProvisioning").val($stageEl.find('#jobProvisioningForm').val());
$('#pipeline-library').val($stageEl.find('#pipelineLibraryNameForm').val()).change();
$('#pipeline-library-branches').val($stageEl.find('#pipelineLibraryBranchForm').val()).change();
let qualityGateData = collectOldQualityGatesData($stageEl);
createQualityGateRows(qualityGateData);
}
function collectOldQualityGatesData($stageEl) {
let $qualityGateTypeEl = $stageEl.find('.qualityGateType'),
$stepNameEl = $stageEl.find('.stepName'),
$autotestsNameEl = $stageEl.find('.autotestsName'),
$branchNameEl = $stageEl.find('.branchName');
let result = [];
$.each($qualityGateTypeEl, function (i) {
result.push({
qualityGateType: $(this).val(),
stepName: $($stepNameEl[i]).val(),
autotestName: $(this).val() === 'autotests' ? $($autotestsNameEl[i]).val() : null,
branchName: $(this).val() === 'autotests' ? $($branchNameEl[i]).val() : null
});
});
return result;
}
function createQualityGateRows(qualityGateData) {
for (let i = 0; i < qualityGateData.length - 1; i++) {
let $firstQualityGateRowEl = $('.quality-gate-row:first').clone(true);
$firstQualityGateRowEl.insertBefore($('.step-name-validation-msg'));
}
let $readyToFillRowElems = $('.quality-gate-row');
$.each($readyToFillRowElems, function (i) {
if (i !== 0) {
$(this).find('.qualityGateTypeLabel, .nameOfStepLabel, .autotestLabel, .branchLabel').remove();
$(this).find('.remove-quality-gate-type').show();
}
$(this).find('.qualityGateType').val(qualityGateData[i].qualityGateType);
$(this).find('.nameOfStep').val(qualityGateData[i].stepName);
if (qualityGateData[i].qualityGateType === 'autotests') {
$(this).find('.autotest-block-el').removeClass('hide-element');
$(this).find('.autotest-projects').val(qualityGateData[i].autotestName);
$(this).find('.autotest-branches').hide();
$(this).find('[data-selected-autotest="' + qualityGateData[i].autotestName + '"]').show();
$(this).find('[data-selected-autotest="' + qualityGateData[i].autotestName + '"]').val(qualityGateData[i].branchName);
}
});
}
function toggleAdding() {
$('.stage-info input[data-mode="edit"]').attr('data-mode', 'add');
$('#add-header').show();
$('#edit-header').hide();
$('button.add-stage').show();
$('button.confirm-edit-stage').hide();
}
function toggleEditing() {
$('#add-header').hide();
$('#edit-header').show();
$('button.add-stage').hide();
$('button.confirm-edit-stage').show();
}
function collectStageData() {
let pipelineLibrary = $('#pipeline-library').val();
return {
stageName: $('#stageName').val(),
stageDesc: $('#stageDesc').val(),
pipelineLibraryName: $('#pipeline-library').val(),
pipelineLibraryBranch: pipelineLibrary === 'default' ? null : $('.pipeline-library-row').find('[data-selected-pipeline-library="' + pipelineLibrary + '"]').val(),
triggerType: $('#triggerType').val(),
jobProvisioning: $('#jobProvisioning').val(),
qualityGates: collectQualityGates(),
};
}
function collectQualityGates() {
let result = [];
$.each($('.quality-gate-row'), function () {
let qualityGateType = $(this).find('.qualityGateType').val();
result.push({
qualityGateType: qualityGateType,
stepName: $(this).find('.nameOfStep').val(),
autotestName: qualityGateType === 'autotests' ? $(this).find('.autotest-projects').val() : null,
branchName: qualityGateType === 'autotests' ? $(this).find('[data-selected-autotest="' + $(this).find('.autotest-projects').val() + '"]').val() : null
});
});
return result;
}
function handleStageNameValidation() {
let $stageNameEl = $('#stageName');
let valid = isStageNameValid();
if (!valid) {
$stageNameEl.addClass('non-valid-input');
$stageNameEl.parents('div.form-group').find('.invalid-feedback.stage-name-msg').show();
} else {
$stageNameEl.removeClass('non-valid-input');
$stageNameEl.parents('div.form-group').find('.invalid-feedback.stage-name-msg').hide();
}
return valid;
}
function handleStageDescriptionValidation() {
let $stageDescEl = $('#stageDesc');
let valid = isStageDescriptionValid();
if (!valid) {
$stageDescEl.addClass('non-valid-input');
$stageDescEl.parents('div.form-group').find('.invalid-feedback').show();
} else {
$stageDescEl.removeClass('non-valid-input');
$stageDescEl.parents('div.form-group').find('.invalid-feedback').hide();
}
return valid;
}
function handleStepNameValidation() {
let $nameOfStepElems = $('.nameOfStep'),
$validationMsgEl = $('.step-name-validation-msg'),
$duplicateValidationMsgEl = $('.duplicate-step-name-validation-msg'),
isValid = true;
$.each($nameOfStepElems, function () {
let isStepNameValid = isFieldValid($(this), /^[a-z0-9]([-a-z0-9]*[a-z0-9])$/);
if (!isStepNameValid) {
isValid = false;
$(this).addClass('non-valid-input');
$validationMsgEl.show();
} else {
$(this).removeClass('non-valid-input');
}
});
if (!isValid) {
return false
}
let nameOfStepArr = getValues($nameOfStepElems),
duplicateErr = doesArrayContainDuplicates(nameOfStepArr);
if (duplicateErr) {
$nameOfStepElems.addClass('non-valid-input');
$duplicateValidationMsgEl.show();
} else {
$nameOfStepElems.removeClass('non-valid-input');
$duplicateValidationMsgEl.hide();
}
if (isValid) {
$validationMsgEl.hide();
}
return isValid && !duplicateErr;
}
function getValues($elemsArray) {
let result = [];
$.each($elemsArray, function () {
result.push($(this).val());
});
return result
}
function doesArrayContainDuplicates(arr) {
let sortedArr = arr.sort();
let duplicates = [];
for (let i = 0; i < sortedArr.length - 1; i++) {
if (sortedArr[i + 1] === sortedArr[i]) {
duplicates.push(sortedArr[i]);
}
}
return duplicates.length > 0;
}
function isStageNameValid() {
let checkStageName = function (stageName) {
return /^[a-z0-9]([-a-z0-9]*[a-z0-9])$/.test(stageName);
};
let $stageNameEl = $('#stageName');
return !(!$stageNameEl.val() || !checkStageName($stageNameEl.val()));
}
function isStageDescriptionValid() {
let $stageDescriptionEl = $('#stageDesc');
return $stageDescriptionEl.val().length !== 0;
}