373 lines
22 KiB
JavaScript
373 lines
22 KiB
JavaScript
"use strict";
|
|
/**
|
|
* Created by andey on 19-08-2017.
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
angular.module('layoutConfigModule')
|
|
.controller('StatusBarController', ['$scope', 'events', 'objectValueMapperService', 'fieldValidationModel',
|
|
'ticketModel', '$rootScope', '$modal', 'screenConfigurationModel',
|
|
function ($scope, events, objectValueMapperService, fieldValidationModel, ticketModel, $rootScope, $modal, screenConfigurationModel) {
|
|
var originalStatus, originalStatusReason;
|
|
var selected = {
|
|
status: null,
|
|
statusReason: null,
|
|
resolutionNote: null
|
|
}, statusField = new FieldVO().build({
|
|
name: $scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatus' : 'status',
|
|
type: 'characterField',
|
|
dataType: 'text',
|
|
ootb: true,
|
|
editable: true,
|
|
readOnly: false
|
|
}), validStatuses, originalTicket;
|
|
if ($scope.data) {
|
|
statusField = angular.copy($scope.data);
|
|
}
|
|
$scope.statusField = statusField;
|
|
$scope.defaultResolutionNoteLength = 250;
|
|
$scope.displayTruncatedText = false;
|
|
$scope.isStatusDisabled = function () {
|
|
return $scope.ticket.accessMappings.allEditAllowed === false || ($scope.ticket.type === EntityVO.TYPE_TASK
|
|
? $scope.ticket.accessMappings.fieldMappings.taskStatus === 'read'
|
|
: $scope.ticket.accessMappings.fieldMappings.status === 'read');
|
|
};
|
|
$scope.isStatusReasonDisabled = function () {
|
|
return $scope.ticket.accessMappings.allEditAllowed === false || ($scope.ticket.type === EntityVO.TYPE_TASK
|
|
? $scope.ticket.accessMappings.fieldMappings.taskStatusReason === 'read'
|
|
: $scope.ticket.accessMappings.fieldMappings.statusReason === 'read');
|
|
};
|
|
$scope.isResolutionDisabled = function () {
|
|
return $scope.ticket.accessMappings.fieldMappings.statusReason === 'read';
|
|
};
|
|
var statusReasonField = new FieldVO().build({
|
|
name: $scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatusReason' : 'statusReason',
|
|
type: 'characterField',
|
|
dataType: 'text',
|
|
ootb: true
|
|
}), resolutionNoteField = new FieldVO().build({
|
|
name: 'resolution',
|
|
type: 'characterField',
|
|
dataType: 'text',
|
|
ootb: true
|
|
});
|
|
$scope.statusReasonField = statusReasonField;
|
|
function init() {
|
|
selected.status = _.cloneDeep(_.find($scope.metadata.statuses, { name: $scope.ticket.status.value }));
|
|
originalStatus = _.cloneDeep(selected.status);
|
|
if (!_.isEmpty(selected.status)) {
|
|
selected.statusReason = _.find(selected.status.statusReasons, { name: $scope.ticket.status.reason });
|
|
if ($scope.ticket.status.reason && !selected.statusReason) {
|
|
var screenName = screenConfigurationModel.getScreenNameByTicketType($scope.ticket.type), screenPanels = screenConfigurationModel.screensCacheByName[screenName]
|
|
? screenConfigurationModel.screensCacheByName[screenName].panels : [], statusFieldFull, statusReasonFieldFull;
|
|
_.forEach(screenPanels, function (panel) {
|
|
statusFieldFull = _.findLast(panel.fields, { name: 'status' });
|
|
if (statusFieldFull) {
|
|
return false;
|
|
}
|
|
});
|
|
statusReasonFieldFull = _.find(statusFieldFull.members, { name: statusReasonField.name });
|
|
selected.statusReason = _.find(statusReasonFieldFull.options, { name: $scope.ticket.status.reason });
|
|
}
|
|
}
|
|
else {
|
|
selected.statusReason = null;
|
|
}
|
|
originalStatusReason = _.cloneDeep(selected.statusReason);
|
|
selected.resolutionNote = $scope.ticket.resolution ? $scope.ticket.resolution : '';
|
|
selected.resolutionNoteLength = selected.resolutionNote ? selected.resolutionNote.length : 0;
|
|
if (selected.resolutionNoteLength > $scope.defaultResolutionNoteLength) {
|
|
$scope.displayTruncatedText = true;
|
|
}
|
|
if (selected.status && selected.status.invalidStatusTransitions && selected.status.invalidStatusTransitions.length) {
|
|
$scope.availableStatuses = _.filter($scope.metadata.statuses, function (status) {
|
|
return ~_.indexOf(selected.status.invalidStatusTransitions, status.name) ? false : true;
|
|
});
|
|
}
|
|
else if (selected.status && selected.status.validKnowledgeTransitions) {
|
|
if (selected.status.validKnowledgeTransitions.length) {
|
|
$scope.availableStatuses = _.filter($scope.metadata.statuses, function (status) {
|
|
return _.find(selected.status.validKnowledgeTransitions, { validStatus: status.name });
|
|
});
|
|
}
|
|
else {
|
|
$scope.availableStatuses = [];
|
|
}
|
|
}
|
|
else if ($scope.ticket.type === EntityVO.TYPE_CHANGE || (($scope.ticket.type === EntityVO.TYPE_PROBLEM || $scope.ticket.type === EntityVO.TYPE_KNOWNERROR) && !$scope.isDraft)) {
|
|
ticketModel.getAvailableStatuses($scope.ticket.id, $scope.ticket.type).then(function (validStatuses) {
|
|
$scope.availableStatuses = _.filter($scope.metadata.statuses, function (status) {
|
|
return validStatuses.indexOf(status.name) !== -1;
|
|
});
|
|
});
|
|
}
|
|
else if ($scope.ticket.type === EntityVO.TYPE_RELEASE && !$scope.isDraft) {
|
|
$scope.availableMilestoneStatuses = _.filter($scope.metadata.milestones, function (milestone) {
|
|
return _.findIndex(validStatuses, { milestone: milestone.name }) !== -1;
|
|
});
|
|
$scope.changeMileStone(selected.milestone, 'release');
|
|
}
|
|
else {
|
|
$scope.availableStatuses = $scope.metadata.statuses;
|
|
}
|
|
statusField.value = selected.status && selected.status.name;
|
|
statusReasonField.value = selected.statusReason && selected.statusReason.name;
|
|
resolutionNoteField.value = selected.resolutionNote;
|
|
objectValueMapperService.addFields([statusField, statusReasonField, resolutionNoteField]);
|
|
$scope.selected = selected;
|
|
statusField.value = selected.status && selected.status.name;
|
|
statusReasonField.value = selected.statusReason ? selected.statusReason.name : '';
|
|
resolutionNoteField.value = selected.resolutionNote || '';
|
|
if (selected.status && selected.status.name === 'Pending' && selected.status.statusReasons) {
|
|
_.remove(selected.status.statusReasons, function (reason) {
|
|
return reason.name === 'Pending Original Incident';
|
|
});
|
|
}
|
|
}
|
|
init();
|
|
$scope.loadMore = function () {
|
|
$scope.selected.expanded = (_.isUndefined($scope.selected.expanded)) ? true : !$scope.selected.expanded;
|
|
};
|
|
$scope.$watch('statusField.setValueFlag', function (value) {
|
|
var status;
|
|
if (value !== '#$#') {
|
|
if (value) {
|
|
status = _.find($scope.metadata.statuses, { name: value });
|
|
if (status) {
|
|
$scope.changeStatus(status);
|
|
}
|
|
}
|
|
$scope.statusField.setValueFlag = '#$#';
|
|
}
|
|
});
|
|
$scope.$watch('statusReasonField.setValueFlag', function (value) {
|
|
var statusReason;
|
|
if (value !== '#$#') {
|
|
if (value) {
|
|
statusReason = _.find(selected.status.statusReasons, { name: value });
|
|
if (statusReason) {
|
|
$scope.changeStatusReason(statusReason);
|
|
}
|
|
}
|
|
$scope.statusReasonField.setValueFlag = '#$#';
|
|
}
|
|
});
|
|
$scope.changeStatus = function (status) {
|
|
selected.status = status;
|
|
selected.statusReason = null;
|
|
if ($scope.ticket.type && $scope.ticket.type === 'incident' && $scope.ticket.resolution === null && (selected.status.name !== 'Closed' && selected.status.name !== 'Resolved')) {
|
|
selected.resolutionNote = '';
|
|
$scope.changeResolutionNote();
|
|
}
|
|
var statusField = objectValueMapperService.getFieldByName($scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatus' : 'status');
|
|
statusField.value = selected.status.name;
|
|
//set the status reason field value on status change, otherwise the expressions are not evaluated correctly
|
|
var statusReasonField = objectValueMapperService.getFieldByName($scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatusReason' : 'statusReason');
|
|
statusReasonField.value = selected.statusReason && selected.statusReason.name;
|
|
var memberName = $scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatus' : 'status';
|
|
$scope.$emit(events.WIDGET_VALUE_CHANGE, { fieldName: statusField.name, memberName: memberName });
|
|
$scope.fixScheduledDates = $scope.ticket.type === 'change' && selected.status.name === 'Scheduled For Review'
|
|
&& (($scope.ticket.scheduledStartDate && $scope.ticket.scheduledStartDate.valueOf() <= $scope.ticket.earliestStartDate)
|
|
|| ($scope.ticket.scheduledEndDate && $scope.ticket.scheduledEndDate.valueOf() <= $scope.ticket.earliestStartDate));
|
|
if ($scope.ticket.type && $scope.ticket.type === 'change' && selected.status.name === 'Completed') {
|
|
selected.statusReason = _.find(status.statusReasons, { name: 'Final Review Required' });
|
|
}
|
|
if (selected.status && selected.status.name === 'Pending' && selected.status.statusReasons) {
|
|
_.remove(selected.status.statusReasons, function (reason) {
|
|
return reason.name === 'Pending Original Incident';
|
|
});
|
|
}
|
|
};
|
|
$scope.changeStatusReason = function (statusReason) {
|
|
selected.statusReason = statusReason;
|
|
var statusReasonField = objectValueMapperService.getFieldByName($scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatusReason' : 'statusReason');
|
|
statusReasonField.value = selected.statusReason.name;
|
|
var memberName = $scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatusReason' : 'statusReason';
|
|
$scope.$emit(events.WIDGET_VALUE_CHANGE, { fieldName: statusReasonField.name, memberName: memberName });
|
|
};
|
|
$scope.changeResolutionNote = function () {
|
|
var resolutionNoteField = objectValueMapperService.getFieldByName('resolution');
|
|
resolutionNoteField.value = selected.resolutionNote;
|
|
$scope.$emit(events.WIDGET_VALUE_CHANGE, { fieldName: resolutionNoteField.name, memberName: 'resolution' });
|
|
};
|
|
$scope.needResolutionNote = function () {
|
|
return ($scope.ticket.type === EntityVO.TYPE_INCIDENT) && (~[EntityVO.STATUS_CLOSED, EntityVO.STATUS_RESOLVED].indexOf(selected.status.name.toLowerCase()) || !_.isEmpty($scope.ticket.resolution));
|
|
};
|
|
$scope.isFieldRequired = function (fieldName) {
|
|
if (fieldName === 'statusReason') {
|
|
if ($scope.ticket.type === EntityVO.TYPE_INCIDENT || $scope.ticket.type === EntityVO.TYPE_CHANGE || $scope.ticket.type === EntityVO.TYPE_RELEASE
|
|
|| $scope.ticket.type === EntityVO.TYPE_PROBLEM || $scope.ticket.type === EntityVO.TYPE_TASK || $scope.ticket.type === EntityVO.TYPE_KNOWNERROR) {
|
|
return fieldValidationModel.isFieldRequired($scope.ticket.type, $scope.selected.status.name, $scope.ticket.timing, fieldName);
|
|
}
|
|
else if ($scope.ticket.type === EntityVO.TYPE_WORKORDER || $scope.ticket.type === EntityVO.TYPE_ACTIVITY) {
|
|
return false;
|
|
}
|
|
else {
|
|
return true;
|
|
}
|
|
}
|
|
//only show when moving from a status where it's not required to a status where it's required
|
|
return fieldValidationModel.isFieldRequired($scope.ticket.type, $scope.ticket.status.value, $scope.ticket.timing, fieldName)
|
|
&& !fieldValidationModel.isFieldRequired($scope.ticket.type, originalTicket.status.value, $scope.ticket.timing, fieldName);
|
|
};
|
|
$scope.switchState = function (direction, ticketType) {
|
|
var currentStatusIndex, switchToState = {}, prevStatusIndex, nextStatusIndex;
|
|
if (ticketType !== 'release') {
|
|
currentStatusIndex = _.findIndex($scope.availableStatuses, function (status) {
|
|
return status.index === $scope.selected.status.index;
|
|
});
|
|
}
|
|
else {
|
|
currentStatusIndex = _.findIndex($scope.availableMilestoneStatuses, function (status) {
|
|
return status.index === $scope.selected.milestone.index;
|
|
});
|
|
}
|
|
if (currentStatusIndex !== -1) {
|
|
if (direction === 'prev') {
|
|
if ((ticketType === 'change' || ticketType === 'problem')
|
|
&& $scope.availableStatuses[currentStatusIndex].name === 'Completed') {
|
|
prevStatusIndex = currentStatusIndex !== 0 ? parseInt(currentStatusIndex - 2) : 0;
|
|
}
|
|
else {
|
|
prevStatusIndex = currentStatusIndex !== 0 ? parseInt(currentStatusIndex - 1) : 0;
|
|
}
|
|
if (ticketType === 'release') {
|
|
switchToState = $scope.availableMilestoneStatuses[prevStatusIndex] || {};
|
|
}
|
|
else {
|
|
switchToState = $scope.availableStatuses[prevStatusIndex] || {};
|
|
}
|
|
}
|
|
else if (direction === 'next') {
|
|
if (((ticketType === 'change' && ($scope.availableStatuses[currentStatusIndex].name === 'Implementation In Progress'
|
|
|| $scope.availableStatuses[currentStatusIndex].name === 'Planning In Progress')) || ticketType === 'problem')
|
|
&& $scope.availableStatuses[currentStatusIndex + 1]
|
|
&& $scope.availableStatuses[currentStatusIndex + 1].name === 'Pending') {
|
|
nextStatusIndex = currentStatusIndex !== $scope.availableStatuses.length - 1 ? parseInt(currentStatusIndex + 2) : $scope.availableStatuses.length - 1;
|
|
}
|
|
else {
|
|
nextStatusIndex = currentStatusIndex !== $scope.availableStatuses.length - 1 ? parseInt(currentStatusIndex + 1) : $scope.availableStatuses.length - 1;
|
|
}
|
|
if (ticketType === 'release') {
|
|
switchToState = $scope.availableMilestoneStatuses[nextStatusIndex] || {};
|
|
}
|
|
else {
|
|
switchToState = $scope.availableStatuses[nextStatusIndex] || {};
|
|
}
|
|
}
|
|
}
|
|
if (ticketType !== 'release') {
|
|
$scope.changeStatus(switchToState, ticketType);
|
|
}
|
|
else {
|
|
selected.status = {};
|
|
$scope.changeMileStone(switchToState, ticketType);
|
|
}
|
|
};
|
|
$scope.clearStatusReason = function (item) {
|
|
var statusReasonField = objectValueMapperService.getFieldByName($scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatusReason' : 'statusReason');
|
|
statusReasonField.value = "";
|
|
};
|
|
$scope.checkStatusSwitcherIsDisabled = function (type, ticketType) {
|
|
var noSwitchStatuses = ['Pending', 'Cancelled', 'Closed', 'Rejected'], currentStatusIndex, nextStatusIndex, nextStatus;
|
|
if (ticketType !== 'release') {
|
|
currentStatusIndex = _.findIndex($scope.availableStatuses, function (status) {
|
|
return status.index === $scope.selected.status.index;
|
|
});
|
|
}
|
|
else {
|
|
currentStatusIndex = _.findIndex($scope.availableMilestoneStatuses, function (status) {
|
|
return status.index === $scope.selected.milestone.index;
|
|
});
|
|
}
|
|
if (currentStatusIndex !== -1 && ticketType !== 'release') {
|
|
if (type === 'prev') {
|
|
return ((currentStatusIndex === 0)
|
|
|| noSwitchStatuses.indexOf($scope.selected.status.name) >= 0);
|
|
}
|
|
else if (type === 'next') {
|
|
if (((ticketType === 'change'
|
|
&& ($scope.availableStatuses[currentStatusIndex].name === 'Implementation In Progress'
|
|
|| $scope.availableStatuses[currentStatusIndex].name === 'Planning In Progress'))
|
|
|| (ticketType === 'problem' || ticketType === 'knownerror'))
|
|
&& $scope.availableStatuses[currentStatusIndex + 1]
|
|
&& ($scope.availableStatuses[currentStatusIndex + 1].name === 'Pending'
|
|
|| $scope.availableStatuses[currentStatusIndex + 1].name === 'Cancelled')) {
|
|
nextStatusIndex = parseInt(currentStatusIndex + 2);
|
|
nextStatus = $scope.availableStatuses[nextStatusIndex] || {};
|
|
}
|
|
else {
|
|
nextStatusIndex = parseInt(currentStatusIndex + 1);
|
|
nextStatus = $scope.availableStatuses[nextStatusIndex] || {};
|
|
}
|
|
if ($scope.selected.status.name === 'Completed' && nextStatus.name === 'Closed') {
|
|
return (noSwitchStatuses.indexOf($scope.selected.status.name) >= 0);
|
|
}
|
|
else {
|
|
return (noSwitchStatuses.indexOf(nextStatus.name) >= 0
|
|
|| noSwitchStatuses.indexOf($scope.selected.status.name) >= 0);
|
|
}
|
|
}
|
|
}
|
|
if (currentStatusIndex !== -1 && ticketType === 'release') {
|
|
if (type === 'prev') {
|
|
return (currentStatusIndex === 0);
|
|
}
|
|
else if (type === 'next') {
|
|
nextStatusIndex = parseInt(currentStatusIndex + 1);
|
|
if ($scope.availableMilestoneStatuses[nextStatusIndex] === undefined) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
$scope.$on(events.TOGGLE_EDIT_MODE, handleToggleEditMode);
|
|
$scope.$on(events.AFTER_SAVED_CHANGES, afterSaveChangesHandler);
|
|
$scope.$on(events.DISCARD_CHANGES, handleDiscardChanges);
|
|
var unbindRootScopeListener = $rootScope.$on(events.TICKET_TEMPLATE_UPDATED, function (e, value) {
|
|
selected.status = value.selectedStatus;
|
|
selected.statusReason = value.selectedStatusReason;
|
|
statusField.value = value.selectedStatus.name;
|
|
selected.resolutionNote = value.resolution;
|
|
});
|
|
function handleToggleEditMode() {
|
|
$scope.editMode = true;
|
|
}
|
|
function afterSaveChangesHandler() {
|
|
$scope.editMode = false;
|
|
originalStatus = _.cloneDeep(selected.status);
|
|
originalStatusReason = _.cloneDeep(selected.statusReason);
|
|
}
|
|
function handleDiscardChanges() {
|
|
$scope.editMode = false;
|
|
selected.status = _.cloneDeep(originalStatus);
|
|
selected.statusReason = _.cloneDeep(originalStatusReason);
|
|
init();
|
|
}
|
|
function checkIfValidDates() {
|
|
var scheduledStartTime = $scope.ticket.scheduledStartDate.valueOf(), scheduledEndTime = $scope.ticket.scheduledEndDate.valueOf();
|
|
$scope.fixScheduledDates = $scope.ticket && $scope.ticket.type === 'change'
|
|
&& selected.status.name === 'Scheduled For Review'
|
|
&& (scheduledStartTime <= $scope.ticket.earliestStartDate || scheduledEndTime <= $scope.ticket.earliestStartDate);
|
|
}
|
|
$scope.$watch('ticket.scheduledStartDate', function () {
|
|
if ($scope.ticket && $scope.ticket.type === 'change'
|
|
&& selected.status.name === 'Scheduled For Review' && $scope.ticket.scheduledStartDate) {
|
|
checkIfValidDates();
|
|
}
|
|
});
|
|
$scope.$watch('ticket.scheduledEndDate', function () {
|
|
if ($scope.ticket && $scope.ticket.type === 'change'
|
|
&& selected.status.name === 'Scheduled For Review' && $scope.ticket.scheduledEndDate) {
|
|
checkIfValidDates();
|
|
}
|
|
});
|
|
$scope.editTicketStatus = function () {
|
|
$scope.$emit(events.EDIT_STATUS_CLICK);
|
|
};
|
|
$scope.$on('$destroy', function () {
|
|
unbindRootScopeListener();
|
|
});
|
|
}]);
|
|
})();
|