551 lines
17 KiB
JavaScript
551 lines
17 KiB
JavaScript
'use strict';
|
|
|
|
app
|
|
// form initialization needs to be called after data was loaded and angular updated all inputs with the new values
|
|
.directive('initForm', ['$timeout', function ($timeout) {
|
|
return {
|
|
link: function ($scope, elem, attrs, ctrl) {
|
|
$scope.$on('dataloaded', function () {
|
|
// need to queue form initialization after DOM rendering (even with timeout=0 action will be placed in the queue of browser actions)
|
|
$timeout(function () {
|
|
if (initMixForm && typeof initMixForm === 'function')
|
|
initMixForm();
|
|
});
|
|
});
|
|
}
|
|
};
|
|
}]).
|
|
directive('selectedDataChanged', ['$timeout', function ($timeout) {
|
|
return {
|
|
link: function ($scope, element, attrs) {
|
|
$scope.$on('selectedTeamsViewsChanged', function () {
|
|
$timeout(function () { // You might need this timeout to be sure its run after DOM render.
|
|
element.trigger("change");
|
|
}, 0, false);
|
|
})
|
|
}
|
|
};
|
|
}])
|
|
.controller('mixHeaderController', ['$scope', '$rootScope', '$http', '$filter', '$timeout', '$element', function ($scope, $rootScope, $http, $filter, $timeout, $element) {
|
|
var commonErrorMessage = 'An error occurred while processing your request. Please, try again later.',
|
|
emptyGuid = '00000000-0000-0000-0000-000000000000';
|
|
$scope.data = {
|
|
Id: null,
|
|
AvailableTeamsAndViews: [],
|
|
SelectedTeamsAndViews: [],
|
|
DisableScreen: false, // SA. ENV-1067
|
|
DisableDelete: false,
|
|
ShowOpen: false,
|
|
SaveMixHasBeenRequested: false,
|
|
ActivateMixHasBeenRequested: false,
|
|
ShowSaveForm: false,
|
|
IsAvgMode: false, // SA. ENV-1030. Show totals summs as average values
|
|
DataLoaded: false, // SA. ENV-1067
|
|
DataChanged: false // SA. ENV-1153
|
|
};
|
|
|
|
$scope.$watch('data.SelectedMix', function (newValue, oldValue) {
|
|
if (oldValue != newValue) {
|
|
$scope.data.ShowOpen = !!newValue && newValue != $scope.data.Id;
|
|
}
|
|
});
|
|
$scope.$watch('data.Users', function (newValue, oldValue) { // SA. ENV-1153
|
|
if ((oldValue != newValue) && ($scope.canClearMix())) {
|
|
setDataChanged(true);
|
|
}
|
|
});
|
|
|
|
$scope.groupTeamsFn = function (item) {
|
|
return item.Group.Name;
|
|
};
|
|
|
|
$scope.init = function (initData) {
|
|
$scope.data.Id = null;
|
|
$scope.data.DataChanged = false; // SA. ENV-1153
|
|
|
|
if (initData) {
|
|
if (initData.mixId && (initData.mixId.length > 0)) {
|
|
$scope.data.Id = initData.mixId;
|
|
}
|
|
if (initData.showAvgTotals) { // SA. ENV-1030. Totals summs as average
|
|
$scope.data.IsAvgMode = initData.showAvgTotals;
|
|
}
|
|
}
|
|
|
|
if (!isMixSelected()) {
|
|
initPageFilter();
|
|
}
|
|
else {
|
|
jQuery(document).ready(function () { loadMixData(); });
|
|
}
|
|
};
|
|
$scope.lockScreen = function () {
|
|
$scope.data.DisableScreen = true;
|
|
|
|
if (!isUIBlocked()) {
|
|
blockUI();
|
|
}
|
|
}
|
|
$scope.unlockScreen = function () {
|
|
unblockUI();
|
|
$scope.data.DisableScreen = false;
|
|
}
|
|
|
|
// SA. ENV-1153
|
|
$scope.$on('dataChanged', function (event, value) {
|
|
setDataChanged(value);
|
|
});
|
|
|
|
// SA. ENV-1159. Leave teamsAndViewsToSelect = undefined to preserver current filter
|
|
$scope.$on('changeDisplayView', function (event, newStartDate, newEndDate, teamsAndViewsToSelect, callbackFn) {
|
|
if (!$scope.canApplyFilter())
|
|
return;
|
|
|
|
// Incoming dates are as Text
|
|
setFilterDates(newStartDate, newEndDate);
|
|
// SA. ENV-1254
|
|
if (teamsAndViewsToSelect && Array.isArray(teamsAndViewsToSelect) && (teamsAndViewsToSelect.length > 0)) {
|
|
setFilterSelectedTeamsAndViews(teamsAndViewsToSelect);
|
|
}
|
|
|
|
$timeout(function () {
|
|
$scope.applyFilter(callbackFn);
|
|
});
|
|
});
|
|
|
|
$scope.saveMixSuccess = function (data) {
|
|
if (data && data.Id) {
|
|
setDataChanged(false); // SA. ENV-1153
|
|
goToMix(data.Id);
|
|
}
|
|
else {
|
|
// Some unknown problems with mix saving
|
|
showErrorModal('Oops!', 'Unexpected error happend during saving of the Mix. Contact your ' +
|
|
'system administrators for details');
|
|
$scope.unlockScreen();
|
|
}
|
|
}
|
|
$scope.saveMixFailed = function (errorMessage) {
|
|
showErrorModal('Oops!', errorMessage);
|
|
$scope.unlockScreen();
|
|
}
|
|
|
|
$scope.saveChanges = function () {
|
|
// SA. ENV-1067
|
|
$scope.lockScreen();
|
|
|
|
if (canSaveMix && typeof canSaveMix === 'function' && !canSaveMix()) {
|
|
$scope.unlockScreen();
|
|
return;
|
|
}
|
|
|
|
var filterData = getFilter4Saving();
|
|
$rootScope.$broadcast("saveChanges", filterData, $scope.saveMixSuccess, $scope.saveMixFailed);
|
|
};
|
|
|
|
$scope.activateMix = function () {
|
|
// SA. ENV-1067
|
|
$scope.lockScreen();
|
|
|
|
if (canSaveMix && typeof canSaveMix === 'function' && !canSaveMix()) {
|
|
$scope.unlockScreen();
|
|
return;
|
|
}
|
|
|
|
var filterData = getFilter4Saving();
|
|
$rootScope.$broadcast("saveChanges", filterData, activateMix);
|
|
};
|
|
|
|
// SA. ENV-1138
|
|
$scope.deleteUnopenedMix = function () {
|
|
if (!$scope.data.SelectedMix || ($scope.data.SelectedMix.length < 1))
|
|
return;
|
|
|
|
$scope.data.DisableDelete = true;
|
|
var mixId = $scope.data.SelectedMix;
|
|
|
|
try {
|
|
bootbox.confirm("Are you sure you want to delete this mix? This action cannot be undone.",
|
|
function (result) {
|
|
$scope.$apply(function () {
|
|
if (result) {
|
|
$rootScope.$broadcast("deleteMix", mixId, onUnopenedMixDeleted, onUnopenedMixDeleteFailed);
|
|
} else {
|
|
// bootbox is not angular directive so we have to tell angular that scope has been updated
|
|
$scope.data.DisableDelete = false;
|
|
}
|
|
});
|
|
});
|
|
} catch (e) {
|
|
$scope.data.DisableDelete = false;
|
|
showErrorModal('Oops!', commonErrorMessage);
|
|
unblockUI();
|
|
}
|
|
};
|
|
|
|
function onUnopenedMixDeleted() {
|
|
var mixId = $scope.data.SelectedMix;
|
|
|
|
// Remove mix from the AvailableMixes collection
|
|
for (var index = $scope.data.AvailableMixes.length - 1; index >= 0; index--) {
|
|
if ($scope.data.AvailableMixes[index].Value == mixId) {
|
|
$scope.data.AvailableMixes.splice(index, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
$scope.data.DisableDelete = false;
|
|
$scope.data.SelectedMix = undefined;
|
|
// SA. We need to reset selected Mix. To reset select2 value we should find it in the DOM tree and set
|
|
// it's value using jQuery. Angular does all the work, but it can't reset displayed selection in select2,
|
|
// because select2 is a JS-control. So it can't be fully managed with the angular digest model
|
|
$element.find("*[ng-model='data.SelectedMix']").select2("val", "");
|
|
};
|
|
|
|
function onUnopenedMixDeleteFailed() {
|
|
$scope.data.DisableDelete = false;
|
|
};
|
|
|
|
$scope.deleteCurrentMix = function () {
|
|
$scope.data.DisableDelete = true;
|
|
try {
|
|
bootbox.confirm("Are you sure you want to delete this mix? This action cannot be undone.", function (result) {
|
|
$scope.$apply(function () {
|
|
if (result) {
|
|
setDataChanged(false);
|
|
$rootScope.$broadcast("deleteMix", $scope.data.Id, goToMix, onDeleteMixFailure);
|
|
} else {
|
|
// bootbox is not angular directive so we have to tell angular that scope has been updated
|
|
$scope.data.DisableDelete = false;
|
|
}
|
|
});
|
|
});
|
|
} catch (e) {
|
|
$scope.data.DisableDelete = false;
|
|
showErrorModal('Oops!', commonErrorMessage);
|
|
unblockUI();
|
|
}
|
|
};
|
|
function onDeleteMixFailure() {
|
|
$scope.data.DisableDelete = false;
|
|
}
|
|
|
|
function getFilter4Saving() {
|
|
var mixFilter = getMixFilter();
|
|
return {
|
|
Id: $scope.data.Id,
|
|
Name: $scope.data.Name,
|
|
StartDate: mixFilter.StartDate,
|
|
EndDate: mixFilter.EndDate,
|
|
Users: $scope.data.Users,
|
|
Filter: {
|
|
Selection: {
|
|
TeamsViews: mixFilter.TeamsViews,
|
|
AvailableTeams: mixFilter.AvailableTeams,
|
|
StartDate: mixFilter.StartDate,
|
|
EndDate: mixFilter.EndDate
|
|
},
|
|
Variants: {
|
|
AvailableTeamsAndViews: $scope.data.AvailableTeamsAndViews
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
$scope.navigateToMix = function () {
|
|
if (!$scope.data.SelectedMix)
|
|
return;
|
|
|
|
goToMix($scope.data.SelectedMix);
|
|
};
|
|
$scope.navigateToNewMix = function () {
|
|
goToMix();
|
|
};
|
|
$scope.canApplyFilter = function () {
|
|
return (($scope.data.SelectedTeamsAndViews || []).length > 0 &&
|
|
($scope.data.StartDate || null) != null &&
|
|
($scope.data.EndDate || null) != null);
|
|
};
|
|
|
|
// SA. ENV-1067
|
|
$scope.canSaveMix = function () {
|
|
return $scope.canApplyFilter() && $scope.data.IsEditable && $scope.data.DataLoaded;
|
|
};
|
|
// SA. ENV-1067
|
|
$scope.canActivateMix = function () {
|
|
return $scope.canSaveMix();
|
|
};
|
|
// SA. ENV-1143
|
|
$scope.canDeleteMix = function () {
|
|
return $scope.data.IsEditable && $scope.data.DataLoaded && isMixSelected();
|
|
};
|
|
$scope.canClearMix = function () {
|
|
return $scope.data.DataLoaded;
|
|
};
|
|
$scope.applyFilter = function (callbackFn) {
|
|
if ($.isFunction(isValidHeader) && !isValidHeader())
|
|
return;
|
|
|
|
blockUI();
|
|
var mixFilter = getMixFilter();
|
|
$rootScope.$broadcast("filterChanged", mixFilter, $scope.data.AvailableTeamsAndViews, callbackFn);
|
|
$scope.data.DataLoaded = true; // SA. ENV-1067
|
|
|
|
setDataChanged(true); // SA. ENV-1153
|
|
};
|
|
function goToMix(mixId) {
|
|
if (!mixId)
|
|
window.location.href = '/Mix';
|
|
else
|
|
window.location.href = '/Mix?id=' + mixId;
|
|
}
|
|
|
|
function initPageFilter() {
|
|
blockUI();
|
|
|
|
var request = getAntiXSRFRequest('/Mix/GetPageFilter', {});
|
|
try {
|
|
$http(request)
|
|
.success(function (data, status, headers, config) {
|
|
try {
|
|
if (!data) {
|
|
unblockUI();
|
|
return;
|
|
}
|
|
|
|
setMixFilter(data);
|
|
unblockUI();
|
|
} catch (e) {
|
|
unblockUI();
|
|
showErrorModal('Oops!', commonErrorMessage);
|
|
} finally {
|
|
$scope.$broadcast('dataloaded');
|
|
}
|
|
})
|
|
.error(function (data, status, headers, config) {
|
|
unblockUI();
|
|
showErrorModal('Oops!', commonErrorMessage);
|
|
});
|
|
} catch (e) {
|
|
unblockUI();
|
|
showErrorModal('Oops!', commonErrorMessage);
|
|
}
|
|
}
|
|
|
|
function loadMixData() {
|
|
$rootScope.$broadcast('loadMix', $scope.data.Id, setMixFilter);
|
|
}
|
|
|
|
$scope.convertTeam = function () {
|
|
$scope.$apply(function () {
|
|
var newTeam = {
|
|
Id: $('form#editTeamForm #Id').val(),
|
|
TVName: $('form#editTeamForm #Name').val(),
|
|
CompanyId: $('form#editTeamForm #CompanyId').val(),
|
|
CostCenterId: $('form#editTeamForm #CostCenterId').val(),
|
|
ReportToId: $('form#editTeamForm #ReportToId').val(),
|
|
UserId: $('form#editTeamForm #UserId').select2('val'),
|
|
CapacityTeamId: $('form#editTeamForm #CapacityTeamId').val(),
|
|
CopyPlanned: $('form#editTeamForm #CopyPlanned').val(),
|
|
IsNew: true,
|
|
Data: $("#team-container").data("capacityPlanner").getData(),
|
|
Group: {
|
|
Disabled: false,
|
|
Name: 'Teams'
|
|
}
|
|
};
|
|
for (var i = 0; i < $scope.data.AvailableTeamsAndViews.length; i++) {
|
|
if ($scope.data.AvailableTeamsAndViews[i].Id == newTeam.Id)
|
|
return;
|
|
}
|
|
$scope.data.AvailableTeamsAndViews.push(newTeam);
|
|
$scope.data.SelectedTeamsAndViews.push(newTeam);
|
|
if ($scope.canApplyFilter())
|
|
$scope.applyFilter();
|
|
});
|
|
$scope.$broadcast('selectedTeamsViewsChanged');
|
|
};
|
|
|
|
$scope.requestMixSaving = function () {
|
|
$scope.data.ShowSaveForm = true;
|
|
$scope.data.SaveMixHasBeenRequested = true;
|
|
$scope.data.ActivateMixHasBeenRequested = false;
|
|
};
|
|
|
|
$scope.requestMixActivation = function () {
|
|
$scope.data.ShowSaveForm = !isMixSelected();
|
|
$scope.data.SaveMixHasBeenRequested = false;
|
|
$scope.data.ActivateMixHasBeenRequested = true;
|
|
};
|
|
|
|
function getMixFilter() {
|
|
var startDate = new Date($scope.data.StartDate);
|
|
var endDate = new Date($scope.data.EndDate);
|
|
|
|
var filter = {
|
|
StartDate: Date.UTC(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()),
|
|
EndDate: Date.UTC(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()),
|
|
TeamsViews: []
|
|
};
|
|
|
|
filter.TeamsViews = $scope.data.SelectedTeamsAndViews;
|
|
return filter;
|
|
}
|
|
|
|
function setMixFilter(data) {
|
|
// prefill dropdown with team and view values
|
|
var selectedTeams = [];
|
|
$.each(data.Filter.Selection.TeamsViews || [], function (index, team) {
|
|
var teamId = team.Id;
|
|
var found = false;
|
|
for (var i = 0; i < data.Filter.Variants.AvailableTeamsAndViews.length; i++) {
|
|
if (data.Filter.Variants.AvailableTeamsAndViews[i].Id == teamId) {
|
|
selectedTeams.push(data.Filter.Variants.AvailableTeamsAndViews[i]);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found && team.IsNew) {
|
|
data.Filter.Variants.AvailableTeamsAndViews.push(team);
|
|
selectedTeams.push(team);
|
|
}
|
|
});
|
|
|
|
$scope.data.Id = data.Id;
|
|
$scope.data.Name = data.Name;
|
|
$scope.data.StartDate = data.StartDate > 0 ? $filter('date')(data.StartDate, 'MM/dd/yyyy') : null;
|
|
$scope.data.EndDate = data.EndDate > 0 ? $filter('date')(data.EndDate, 'MM/dd/yyyy') : null;
|
|
$scope.data.Users = data.Users;
|
|
$scope.data.SelectedMix = data.Id;
|
|
|
|
if (data.Filter) {
|
|
if (data.Filter.Variants) {
|
|
$scope.data.AvailableTeamsAndViews = data.Filter.Variants.AvailableTeamsAndViews;
|
|
$scope.data.AvailableUsers = data.Filter.Variants.AvailableUsers;
|
|
$scope.data.AvailableMixes = data.Filter.Variants.AvailableMixes;
|
|
$scope.data.IsEditable = data.Filter.Variants.IsEditable;
|
|
}
|
|
|
|
if (data.Filter.Selection) {
|
|
$scope.data.SelectedTeamsAndViews = selectedTeams;
|
|
}
|
|
}
|
|
|
|
var mixSelected = isMixSelected();
|
|
$scope.data.DataLoaded = mixSelected; // SA. ENV-1067
|
|
|
|
$timeout(function () {
|
|
// SA. ENV-1153. Reset changes flag. Code must be executed last after loading mix data.
|
|
// Queue its' execution after all watchers
|
|
setDataChanged(false);
|
|
});
|
|
}
|
|
|
|
function isMixSelected() {
|
|
return !!$scope.data.Id && $scope.data.Id != emptyGuid;
|
|
}
|
|
|
|
function activateMix(data) {
|
|
$scope.lockScreen();
|
|
|
|
if (!data || !data.Id) {
|
|
$scope.unlockScreen();
|
|
return;
|
|
}
|
|
|
|
var mixId = data.Id;
|
|
var request = getAntiXSRFRequest('/Mix/ActivateMix', mixId);
|
|
try {
|
|
$http(request)
|
|
.success(function (data, status, headers, config) {
|
|
|
|
try {
|
|
$scope.unlockScreen();
|
|
bootbox.alert('Mix have been activated successfully', function () {
|
|
setDataChanged(false);
|
|
goToMix(mixId);
|
|
});
|
|
} catch (e) {
|
|
$scope.unlockScreen();
|
|
showErrorModal('Oops!', commonErrorMessage);
|
|
}
|
|
})
|
|
.error(function (data, status, headers, config) {
|
|
$scope.unlockScreen();
|
|
showErrorModal('Oops!', commonErrorMessage);
|
|
});
|
|
} catch (e) {
|
|
$scope.unlockScreen();
|
|
showErrorModal('Oops!', commonErrorMessage);
|
|
}
|
|
}
|
|
|
|
// SA. ENV-1153
|
|
function setDataChanged(value) {
|
|
$scope.data.DataChanged = value;
|
|
|
|
if (value) {
|
|
addPageLeaveHandler();
|
|
}
|
|
else {
|
|
removePageLeaveHandler();
|
|
}
|
|
}
|
|
|
|
function addPageLeaveHandler() {
|
|
window.onbeforeunload = function (e) {
|
|
var message = "Mix contains unsaved changes. Are you sure you want to leave the page?",
|
|
e = e || window.event;
|
|
// For IE and Firefox
|
|
if (e) {
|
|
e.returnValue = message;
|
|
}
|
|
|
|
// For Safari
|
|
return message;
|
|
};
|
|
}
|
|
|
|
function removePageLeaveHandler() {
|
|
window.onbeforeunload = null;
|
|
}
|
|
|
|
// SA. ENV-1159
|
|
function setFilterDates(startDate, endDate) {
|
|
// Dates are as Text
|
|
if (startDate && (startDate.length > 0)) {
|
|
$scope.data.StartDate = startDate;
|
|
var startDateObj = new Date(startDate);
|
|
$element.find("#MixStartDate").data('datepicker').setDate(startDateObj);
|
|
}
|
|
|
|
if (endDate && (endDate.length > 0)) {
|
|
$scope.data.EndDate = endDate;
|
|
var endDateObj = new Date(endDate);
|
|
$element.find("#MixEndDate").data('datepicker').setDate(endDateObj);
|
|
}
|
|
}
|
|
|
|
// SA. ENV-1254
|
|
function setFilterSelectedTeamsAndViews(teamsAndViews) {
|
|
if (!teamsAndViews || !Array.isArray(teamsAndViews) || (teamsAndViews.length < 1))
|
|
return;
|
|
var visualSelection = [];
|
|
var selectedTeams = $.grep($scope.data.AvailableTeamsAndViews, function (teamViewItem, index) {
|
|
var found = teamsAndViews.indexOf(teamViewItem.Id) >= 0;
|
|
|
|
if (found) {
|
|
var sortedIndex = $("select#selectedTeamViews").find("option:contains('" + teamViewItem.TVName + "')").val();
|
|
|
|
if (sortedIndex !== undefined)
|
|
visualSelection.push(sortedIndex);
|
|
}
|
|
|
|
return found;
|
|
});
|
|
|
|
$scope.data.SelectedTeamsAndViews = selectedTeams;
|
|
$('#selectedTeamViews').select2('val', visualSelection);
|
|
}
|
|
}]); |