SmartIT_Extensions/BMC/smart-it-full-helix/scripts/app/release/create-release-controller.js

673 lines
34 KiB
JavaScript

"use strict";
/**
* Created by andey on 14-11-2016.
*/
(function () {
'use strict';
angular.module('releaseModule')
.controller('CreateReleaseController', ['$scope', '$rootScope', '$state', '$q', '$http', '$modal', '$timeout', 'releaseTabIds', 'userModel', 'searchModel', 'metadataModel',
'ticketModel', 'createTicketModel', 'ticketActionService', 'categoriesService', 'editTicketDatesService', 'ticketTemplateModel',
'ticketService', 'systemAlertService', 'events', 'localStorageService', 'i18nService', 'configurationModel', '$filter', 'feedModel', 'utilityFunctions',
function ($scope, $rootScope, $state, $q, $http, $modal, $timeout, releaseTabIds, userModel, searchModel, metadataModel, ticketModel, createTicketModel, ticketActionService, categoriesService, editTicketDatesService, ticketTemplateModel, ticketService, systemAlertService, events, localStorageService, i18nService, configurationModel, $filter, feedModel, utilityFunctions) {
$state.go('createRelease.selector');
$scope.tabIds = releaseTabIds;
$scope.draftTicket = {
type: EntityVO.TYPE_RELEASE
};
$scope.selections = {
companies: []
};
$scope.siteOptions = {
company: {
visible: false,
attribute: 'companyName'
},
region: {
attribute: 'region'
},
siteGroup: {
attribute: 'siteGroup'
},
site: {
attribute: 'name'
}
};
$scope.validator = editTicketDatesService;
$scope.releasePlanMilestoneDirty = false;
$scope.createDraftRelease = function () {
$scope.state.dataIsLoading = true;
$scope.draftCreated = false;
$scope.isNew = true;
var templateId = null;
if ($scope.selectedMainTab !== $scope.tabIds.main.scratch) {
templateId = $scope.template.selected.id;
}
getDraftPromise(templateId).then(function (response) {
$scope.state.dataIsLoading = false;
var isTemplate = !_.isEmpty(templateId);
objectifyDraftTicket(response, isTemplate);
$scope.template.selected.forCompany = $scope.draftTicket.company.name;
if ($scope.template.selected && $scope.template.selected.id) {
addToLastUsedTemplates($scope.template.selected);
}
$scope.draftCreated = true;
goToWizard();
})
.catch(function (error) {
$scope.state.dataIsLoading = false;
error = error.data.detailedMessage || error.data.error || error;
systemAlertService.error({
text: error,
clear: true
});
});
};
$scope.setCompany = function (company) {
$scope.draftTicket.company = company;
$scope.showRecentTemplates = true;
getlastUsedTemplates(company.name);
};
$scope.selectMainTab = function (tab) {
$scope.selectedMainTab = tab;
};
$scope.releaseWizardValid = function () {
return $scope.invalidFormCount() === 0;
};
$scope.invalidFormCount = function () {
var count = 0;
_.forOwn($scope.tabIds.wizard, function (value, tabId) {
if (!$scope.formValid(tabId)) {
count++;
}
});
return count;
};
$scope.isValidSummary = function () {
if ($scope.draftTicket.summary && $scope.draftTicket.summary.length > 0) {
return true;
}
return false;
};
$scope.formValid = function (tabId) {
return $scope[tabId] ? !$scope[tabId].$invalid : true;
};
$scope.formDirty = function (tabId) {
return $scope[tabId] ? $scope[tabId].$dirty : false;
};
$scope.dirtyFormCount = function () {
var count = 0;
for (var tabId in $scope.tabIds.wizard) {
if ($scope.formDirty(tabId)) {
count++;
}
}
return count;
};
$scope.releaseWizardDirty = function () {
return $scope.dirtyFormCount() !== 0 || !_.isEmpty($scope.draftTicket.documents);
};
$scope.$on(events.RELEASE_WIZARD_FORM_STATE, function (event, form) {
$scope[form.name] = $scope[form.name] || {};
if (typeof form.invalid !== 'undefined') {
$scope[form.name].$invalid = form.invalid;
}
if (typeof form.dirty !== 'undefined') {
$scope[form.name].$dirty = form.dirty;
}
});
$scope.clear = function () {
if ($scope.releaseWizardDirty()) {
var modalInstance = displayDirtyFormAlert();
modalInstance.result.then(function (data) {
if (data) {
reset();
}
});
}
else {
reset();
}
};
$scope.clearTemplateSearch = function () {
$scope.template = {
search: '',
list: [],
selected: {},
showSearchResults: false,
preview: null
};
};
$scope.openDatePicker = function (calendar, event) {
calendar.open = true;
event.stopPropagation();
};
$scope.updatePriority = function () {
$scope.state.dataIsLoading = true;
ticketModel.getReleasePriority($scope.draftTicket.company.name, $scope.draftTicket.impact.name, $scope.draftTicket.urgency.name).then(function (data) {
$scope.draftTicket.priority = _.find($scope.releaseMetadata.priorities, { name: data });
if (!$scope.draftTicket.priority) {
systemAlertService.error({
text: $filter('i18n')('create.change.wizard.basicDetails.priority.warning'),
hide: 10000
});
}
$scope.state.dataIsLoading = false;
});
};
$scope.nextStep = function () {
var takeNext = false;
_.forOwn($scope.tabIds.wizard, function (value, tabId) {
if (takeNext) {
takeNext = false;
$scope.state.selectedWizardTab = tabId;
return;
}
if (value === $scope.state.selectedWizardTab) {
takeNext = true;
}
});
};
$scope.isDocumentTab = function () {
return $scope.state.selectedWizardTab === $scope.tabIds.wizard.documents;
};
$scope.getTemplateList = function (query) {
return ticketTemplateModel.getReleaseTemplateList(query, $scope.draftTicket.company.name, $scope.releaseMetadata).then(function (data) {
$scope.state.exceedsChunkSizeTemplates = data.exceedsChunkSize;
$scope.state.isTooltipOpenTemplates = data.exceedsChunkSize;
$timeout(function () {
$scope.state.isTooltipOpenTemplates = false;
}, 10000);
return _.uniqBy(_.map(data.items, 'name'));
});
};
$scope.getRecommendedTemplates = function () {
if (_.isEmpty($scope.template.search)) {
return;
}
$scope.state.templatesLoading = true;
ticketTemplateModel.getReleaseTemplateList($scope.template.search, $scope.draftTicket.company.name, $scope.releaseMetadata).then(function (data) {
$scope.template.list = data.items;
}).finally(function () {
$scope.state.templatesLoading = false;
$scope.template.showSearchResults = true;
});
};
$scope.getList = function (type, term) {
return createTicketModel.getList(type, term).then(function (response) {
if (type === 'service') {
$scope.state.exceedsChunkSizeService = response.exceedsChunkSize;
}
$scope.state.isTooltipOpenService = $scope.state.exceedsChunkSizeService;
$timeout(function () {
$scope.state.isTooltipOpenService = false;
}, 10000);
return response.objects;
});
};
$scope.onInputFocusBlur = function () {
$scope.state.isTooltipOpenService = false;
$scope.state.isTooltipOpenTemplates = false;
};
$scope.getCompaniesByName = function (name) {
return searchModel.getCompaniesByText(name).then(function (response) {
return { list: response.companies, exceedsChunkSize: response.exceedsChunkSize };
});
};
$scope.createBlankActivity = function () {
isReleasePlanDirty(function (status) {
if (status) {
continueWithActivityCreation();
}
});
function continueWithActivityCreation() {
ticketModel.activityParent = $scope.draftTicket;
var modalInstance = $modal.open({
templateUrl: 'views/create/create-activity.html',
controller: 'CreateActivityController',
windowClass: 'ticket__open-modal',
backdrop: false,
keyboard: false
});
modalInstance.result.then(function () {
refreshRelations();
createTicketModel.currentTicket = $scope.draftTicket;
});
}
};
$scope.browseActivityTemplate = function () {
isReleasePlanDirty(function (status) {
if (status) {
continueBrowsingTemplate();
}
});
function continueBrowsingTemplate() {
ticketModel.activityParent = $scope.draftTicket;
var modalInstance = $modal.open({
templateUrl: 'views/template/browse-ticket-template-action-blade.html',
windowClass: 'action-blade',
controller: 'BrowseTicketTemplateController',
resolve: {
ticketType: function () {
return EntityVO.TYPE_ACTIVITY;
},
metadata: function () {
return {};
},
company: function () {
return $scope.draftTicket.company;
}
}
});
modalInstance.result.then(function () {
refreshRelations();
});
}
};
$scope.createRelease = function () {
isReleasePlanDirty(function (status) {
if (status) {
$scope.state.savingRelease = true;
$scope.draftTicket.summary = $scope.draftTicket.summary.replace(/\u00a0/g, ' ');
$scope.draftTicket.categorizations = categoriesService.collectValues($scope.draftTicket.allCategories, $scope.draftTicket, null, true).categorizations;
if ($rootScope.timezone) {
$scope.draftTicket.scheduledStartDate = !$scope.draftTicket.scheduledStartDate ? $scope.draftTicket.scheduledStartDate
: utilityFunctions.convertToUserPreferenceTimezone($scope.draftTicket.scheduledStartDate, $rootScope.timezone);
$scope.draftTicket.scheduledEndDate = !$scope.draftTicket.scheduledEndDate ? $scope.draftTicket.scheduledEndDate
: utilityFunctions.convertToUserPreferenceTimezone($scope.draftTicket.scheduledEndDate, $rootScope.timezone);
$scope.draftTicket.deploymentStartDate = !$scope.draftTicket.deploymentStartDate ? $scope.draftTicket.deploymentStartDate
: utilityFunctions.convertToUserPreferenceTimezone($scope.draftTicket.deploymentStartDate, $rootScope.timezone);
$scope.draftTicket.deploymentEndDate = !$scope.draftTicket.deploymentEndDate ? $scope.draftTicket.deploymentEndDate
: utilityFunctions.convertToUserPreferenceTimezone($scope.draftTicket.deploymentEndDate, $rootScope.timezone);
}
$scope.$broadcast(events.SAVE_TICKET_DRAFT);
createTicketModel.createRelease()
.then(function (release) {
$q.all(createTicketModel.saveDocuments(createTicketModel.currentTicket)).finally(function () {
release.type = EntityVO.TYPE_RELEASE;
processPendingWorkNoteFor(release).finally(function () {
$scope.state.savingRelease = false;
$state.go(EntityVO.TYPE_RELEASE, { id: release.id });
});
});
})
.catch(function (error) {
$scope.state.savingRelease = false;
error = error.data.detailedMessage || error.data.error || error;
systemAlertService.error({
text: error,
clear: true
});
});
}
});
};
$scope.assign = function ($event) {
var currentAssignment = {
supportGroup: $scope.draftTicket.coordinatorGroup,
assignee: $scope.draftTicket.coordinator,
company: $scope.draftTicket.company,
locationCompany: $scope.draftTicket.company,
type: EntityVO.TYPE_RELEASE
};
ticketActionService.showAssignDialog(currentAssignment, true).result.then(function (result) {
if (result.autoAssign) {
$scope.draftTicket.autoAssignAssignee = true;
$scope.draftTicket.coordinator = {};
$scope.draftTicket.coordinatorGroup = {};
}
else {
$scope.draftTicket.autoAssignAssignee = false;
if (result.assignee) {
$scope.draftTicket.coordinator = result.assignee;
}
if (result.group) {
$scope.draftTicket.coordinatorGroup = result.group;
}
}
$scope[releaseTabIds.wizard.basics].$dirty = true;
$event.currentTarget.focus();
}, function () {
$event.currentTarget.focus();
});
};
$scope.assignToMe = function ($event, role) {
var assigneeRole = role;
var assigneeSupportGroup = $scope.draftTicket.coordinatorGroup;
var locationCompany = null, customerCompany, primaryCompany = $scope.draftTicket.company;
primaryCompany = primaryCompany ? primaryCompany.name : '';
customerCompany = ($scope.draftTicket.customer && $scope.draftTicket.customer.company) ? $scope.draftTicket.customer.company.name : ($scope.draftTicket.company ? $scope.draftTicket.company.name : '');
locationCompany = $scope.draftTicket.location && $scope.draftTicket.location.companyName ? $scope.draftTicket.location.companyName : null;
ticketModel.getTicketAssigneePersonsBySearchText(assigneeRole, customerCompany, locationCompany, null, primaryCompany, null).then(function (persons) {
persons = _.uniqBy(persons.results, function (person) {
return person.loginId && person.supportGroupId;
});
var person = persons.length === 1 ? persons[0] : _.find(persons, { supportGroupId: assigneeSupportGroup.id });
if (person && person.loginId) {
updateAssignment(person);
}
else {
handleAssignment($event, role);
}
});
};
$scope.calculateRisk = function (riskLevelSelectionMode) {
if (riskLevelSelectionMode === 'auto') {
ticketService.getReleaseRisk($scope.draftTicket.id).then(function (response) {
if (response.riskLevel === null) {
$scope.draftTicket.isCalculateRiskNull = true;
}
var index = _.findIndex($scope.releaseMetadata.riskLevels, { name: response.riskLevel });
if (index !== -1) {
$scope.draftTicket.titleRiskLevelCls = 'risk-level-' + (index + 1);
$scope.draftTicket.riskLevel = _.find($scope.releaseMetadata.riskLevels, { name: response.riskLevel });
}
else if (!$scope.draftTicket.riskLevel) {
$scope.draftTicket.titleRiskLevelCls = 'risk-level-1';
$scope.draftTicket.riskLevel = $scope.releaseMetadata.riskLevels[0];
}
});
}
else {
$scope.draftTicket.isCalculateRiskNull = false;
}
};
$scope.riskLevel = function () {
return $scope.draftTicket.riskLevel ? $scope.draftTicket.riskLevel.label : '';
};
$scope.addExistingChange = function ($event) {
var modalInstance = $modal.open({
templateUrl: 'views/release/relate-change-action-blade.html',
windowClass: 'action-blade-aif',
controller: 'RelateChangeController',
resolve: {
linkParams: function () {
var sequence = 1;
if ($scope.draftTicket.noOfRelatedItems[$scope.draftTicket.milestone.name]) {
sequence = $scope.draftTicket.noOfRelatedItems[$scope.draftTicket.milestone.name] + 1;
}
return {
selectedItems: [{
id: $scope.draftTicket.id,
type: EntityVO.TYPE_RELEASE,
desc: $scope.draftTicket.summary,
displayId: $scope.draftTicket.displayId,
milestone: $scope.draftTicket.milestone
}],
isDraft: true,
sequence: sequence
};
}
}
});
modalInstance.result.then(function () {
refreshRelations();
}).finally(function () {
$event.currentTarget.focus();
});
};
$scope.$watch('draftTicket.company', function () {
if ($scope.draftTicket.company) {
$scope.template = {
search: '',
list: [],
selected: {},
showSearchResults: false,
preview: null
};
}
});
function isReleasePlanDirty(callback) {
if ($scope.releasePlanMilestoneDirty) {
var modalInstance = displayDirtyFormAlert();
modalInstance.result.then(function (data) {
if (data) {
callback(true);
}
else {
callback(false);
}
});
}
else {
callback(true);
}
}
function displayDirtyFormAlert() {
var modalInstance = systemAlertService.modal({
title: i18nService.getLocalizedString('common.notification.dirty.title'),
text: i18nService.getLocalizedString('common.notification.dirty.message'),
buttons: [
{
text: i18nService.getLocalizedString('common.labels.yes'),
data: true
},
{
text: i18nService.getLocalizedString('common.labels.no')
}
]
});
return modalInstance;
}
function addToLastUsedTemplates(template) {
$scope.lastUsedTemplates.unshift(template);
$scope.lastUsedTemplates = _.uniqBy($scope.lastUsedTemplates, function (item) {
return item.id;
}).splice(0, 50);
localStorageService.set('release.lastUsedTemplates', $scope.lastUsedTemplates);
}
function getlastUsedTemplates(company) {
$scope.state.lastUsedTemplatesLoading = true;
$scope.currentRecentlyUsedTemplates = [];
var templates = _.filter($scope.lastUsedTemplates, { forCompany: company });
if (templates.length) {
ticketModel.getRecentlyUsedReleaseTemplates(templates, $scope.releaseMetadata).then(function (newTemplates) {
$scope.state.lastUsedTemplatesLoading = false;
if (newTemplates) {
$scope.currentRecentlyUsedTemplates = modifyTemplateAttributes(newTemplates);
}
}).catch(function () {
$scope.state.lastUsedTemplatesLoading = false;
});
}
else {
$scope.state.lastUsedTemplatesLoading = false;
}
}
function modifyTemplateAttributes(templates) {
var attributes = ['riskLevel', 'impact', 'urgency', 'releaseType', 'impactedService'];
_.forEach(templates, function (template) {
_.forEach(attributes, function (attr) {
if (!_.isUndefined(template.templateObject[attr])) {
template[attr] = template.templateObject[attr];
}
});
});
return templates;
}
function handleAssignment($event, role) {
var currentAssignment = {
supportGroup: $scope.draftTicket.coordinatorGroup,
assignee: $scope.draftTicket.coordinator,
locationCompany: $scope.draftTicket.company,
type: EntityVO.TYPE_RELEASE
};
ticketActionService.showAssignDialog(currentAssignment, true, role).result.then(function (result) {
completeAssignment(result);
$event.currentTarget.focus();
}, function () {
$event.currentTarget.focus();
});
}
function updateAssignment(person) {
var response = {};
response.assignee = { id: person.id, loginId: person.loginId, fullName: person.fullName, thumbnailMime: person.thumbnailMime, thumbnail: person.thumbnail };
response.group = { id: person.supportGroupId, name: person.supportGroup, organization: person.organization, company: person.company };
completeAssignment(response);
}
function completeAssignment(result) {
if (result.autoAssign) {
$scope.draftTicket.autoAssignAssignee = true;
$scope.draftTicket.coordinator = {};
$scope.draftTicket.coordinatorGroup = {};
}
else {
$scope.draftTicket.autoAssignAssignee = false;
if (result.assignee) {
$scope.draftTicket.coordinator = result.assignee;
}
if (result.group) {
$scope.draftTicket.coordinatorGroup = result.group;
}
}
}
function refreshRelations() {
//TODO: Code to refresh activities and CRQ related to release.
$timeout(function () {
$scope.$broadcast(events.REFRESH_RELEASE_PLAN_LIST);
}, 1000);
}
function getDraftPromise(templateId) {
return ticketService.getDraft(EntityVO.TYPE_RELEASE, templateId);
}
function getLocationAsPerCompanySet() {
if ($scope.draftTicket.company.name === userModel.userFullData.company.name) {
return userModel.userFullData.company.site;
}
else {
return {};
}
}
function objectifyDraftTicket(response, isTemplate) {
if (!isTemplate || !response.company || response.company.name !== $scope.draftTicket.company.name
|| _.isEmpty(response.location)) {
response.location = getLocationAsPerCompanySet();
}
response.company = $scope.draftTicket.company;
$scope.draftTicket = angular.extend($scope.draftTicket, response);
createTicketModel.currentTicket = $scope.draftTicket;
$scope.draftTicket.impact = $scope.draftTicket.impact
? _.head(_.filter($scope.releaseMetadata.impacts, { name: $scope.draftTicket.impact }))
: _.last($scope.releaseMetadata.impacts);
$scope.draftTicket.urgency = $scope.draftTicket.urgency
? _.head(_.filter($scope.releaseMetadata.urgencies, { name: $scope.draftTicket.urgency }))
: _.last($scope.releaseMetadata.urgencies);
initPriority();
$scope.draftTicket.businessJustification = $scope.draftTicket.businessJustification
? _.head(_.filter($scope.releaseMetadata.businessJustifications, { name: $scope.draftTicket.businessJustification }))
: (_.includes($scope.releaseMetadata && $scope.releaseMetadata.requiredOOTBObjectName, 'businessJustification')
? _.head($scope.releaseMetadata.businessJustifications) : null);
$scope.draftTicket.releaseType = $scope.draftTicket.releaseType
? _.head(_.filter($scope.releaseMetadata.types, { name: $scope.draftTicket.releaseType }))
: null;
if ($scope.draftTicket.location) {
$scope.draftTicket.location.companyName = $scope.draftTicket.company.name;
}
if ($scope.draftTicket.riskLevel) {
$scope.draftTicket.riskLevel = _.head(_.filter($scope.releaseMetadata.riskLevels, { name: $scope.draftTicket.riskLevel }));
$scope.draftTicket.riskLevelSelectionMode = 'manual';
}
else {
$scope.draftTicket.riskLevelSelectionMode = 'auto';
$scope.calculateRisk($scope.draftTicket.riskLevelSelectionMode);
}
$scope.draftTicket.allCategories = _.cloneDeep(categoriesService.populateCategories($scope.draftTicket.categorizations, $scope.releaseMetadata));
}
function initPriority() {
if ($scope.draftTicket.priority) {
$scope.draftTicket.priority = _.head(_.filter($scope.releaseMetadata.priorities, { name: $scope.draftTicket.priority }));
}
else {
var lowestImpact = _.last($scope.releaseMetadata.impacts);
var lowestUrgency = _.last($scope.releaseMetadata.urgencies);
if ($scope.draftTicket.impact === lowestImpact && $scope.draftTicket.urgency === lowestUrgency) {
$scope.draftTicket.priority = _.last($scope.releaseMetadata.priorities);
}
else {
$scope.draftTicket.priority = {};
// implement function to fetch priority from backend :: $scope.updatePriority();
}
}
}
function goToWizard() {
$state.go('createRelease.wizard');
}
function reset() {
$scope.selectedMainTab = $scope.tabIds.main.template;
$scope.state.selectedWizardTab = $scope.tabIds.wizard.basics;
$scope.datePickerOptions = {
startingDay: configurationModel.getWeekStartingDay(),
'show-weeks': false,
minDate: moment().year(1970).month(0).date(2),
maxDate: moment().year(2038).month(0).date(18)
};
$scope.template = {
search: '',
list: [],
selected: {},
showSearchResults: false,
preview: null
};
$scope.draftTicket = {
type: EntityVO.TYPE_RELEASE,
scheduledStartDatePicker: { open: false },
scheduledEndDatePicker: { open: false },
deploymentStartDatePicker: { open: false },
deploymentEndDatePicker: { open: false }
};
$scope.draftCreated = false;
$scope.showRecentTemplates = false;
$scope.setCompany(userModel.userFullData.company);
$state.go('createRelease.selector');
}
function processPendingWorkNoteFor(ticket) {
return feedModel.processPendingWorkNote(ticket) || $q.when(1);
}
function init() {
$scope.state = {
dataIsLoading: true,
templatesLoading: false,
tooManyCompanies: false,
savingRelease: false,
lastUsedTemplatesLoading: true
};
var storedTemplates = localStorageService.get('release.lastUsedTemplates');
$scope.lastUsedTemplates = storedTemplates ? storedTemplates : [];
$scope.releaseMetadata = {};
var metadataPromise = metadataModel.getMetadataByType(EntityVO.TYPE_RELEASE).then(function (metadata) {
angular.extend($scope.releaseMetadata, metadata);
if (!$scope.releaseMetadata.documentTypes || $scope.releaseMetadata.documentTypes && $scope.releaseMetadata.documentTypes.length === 0) {
// todo : we need move from mocks to constant for both release and change case.
$http.get('mocks/change-request-metadata-document-types.json')
.then(function (data) {
$scope.releaseMetadata.documentTypes = data.documentTypes;
});
}
});
var userPromise = userModel.getFullCurrentUserData().then(function () {
$scope.loggedInUserId = userModel.decodedUserId || userModel.userId;
$scope.availableForAssignment = userModel.userFullData.availableForAssignment;
searchModel.getOperatingCompanies(null, -1).then(function (response) {
$scope.selections.companies = _.cloneDeep(response.companies);
$scope.state.tooManyCompanies = response.exceedsChunkSize;
});
});
$q.all([metadataPromise, userPromise]).then(function () {
$scope.state.dataIsLoading = false;
reset();
});
}
$scope.$on(events.RELEASE_PLAN_MILESTONE_CHANGE, function () {
$scope.releasePlanMilestoneDirty = true;
});
$scope.$on(events.RELEASE_PLAN_MILESTONE_NOT_DIRTY, function () {
$scope.releasePlanMilestoneDirty = false;
});
$scope.$watch('draftTicket.impactedService', function () {
if ($scope.draftTicket && _.isObject($scope.draftTicket.impactedService)) {
$scope.$emit(events.AFFECTED_SERVICE_UPDATED, $scope.draftTicket.impactedService);
}
});
init();
}]);
})();