428 lines
22 KiB
JavaScript
428 lines
22 KiB
JavaScript
"use strict";
|
|
/**
|
|
* Created by viktor.shevchenko on 12/10/2014.
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
angular.module('createTicketModule')
|
|
.controller('CreateKnowledgeArticleController', ['$scope', 'localStorageService', '$modal', 'searchService', 'relationModel',
|
|
'$state', '$timeout', 'systemAlertService', 'attachmentService', 'metadataModel', 'categoriesService',
|
|
'knowledgeArticleModel', 'ticketModel', '$q', '$filter', 'configurationModel',
|
|
function ($scope, localStorageService, $modal, searchService, relationModel, $state, $timeout, systemAlertService, attachmentService, metadataModel, categoriesService, knowledgeArticleModel, ticketModel, $q, $filter, configurationModel) {
|
|
if (!configurationModel.isServerApplicationEnabled(EntityVO.TYPE_KNOWLEDGE)) {
|
|
$state.go('unauthorized');
|
|
return;
|
|
}
|
|
$scope.editMode = true; //flag that is used for category directive
|
|
var article = {}, metadata, knowledgeTitleChangeTimer, state = {}, localStorageDefaultTemplateKey = 'DEFAULT_KA_TEMPLATE', currentUserId = localStorageService.get('user.userId'), savedTemplate = localStorageService.get(localStorageDefaultTemplateKey), defaultTemplateId = (savedTemplate && (savedTemplate.user === currentUserId)) ? savedTemplate.templateId : null, localStorageLastVisibilitySetKey = 'LAST_SET_OF_VISIBILITY_GROUPS', draftArticle = {};
|
|
setInitialState();
|
|
loadAvailableTemplates().then(function () {
|
|
if (defaultTemplateId) {
|
|
$scope.selectedTemplate = _.find($scope.templates, { id: defaultTemplateId });
|
|
loadDraftData().then(function () {
|
|
state.isTemplateSelected = true;
|
|
state.isTemplateAccepted = true;
|
|
});
|
|
}
|
|
});
|
|
function setInitialState() {
|
|
state = angular.extend(state, {
|
|
dataIsLoading: false,
|
|
isTemplateSelected: false,
|
|
isTemplateAccepted: false,
|
|
rememberTemplate: false,
|
|
showMetadata: true,
|
|
loadingMergeWindow: false,
|
|
showingMergeTool: false,
|
|
similarArticles: [],
|
|
showSimilarArticles: false,
|
|
loadVisibility: false,
|
|
loadingSimilarArticles: false,
|
|
similarArticlePromise: null,
|
|
allowStateChange: false
|
|
});
|
|
$scope.attachments = [];
|
|
$scope.linkedItems = [];
|
|
$scope.titleMaxLength = 4000;
|
|
}
|
|
function loadAvailableTemplates() {
|
|
state.dataIsLoading = true;
|
|
return knowledgeArticleModel.getKnowledgeArticleTemplates().then(function (templates) {
|
|
$scope.templates = angular.copy(templates);
|
|
_.remove($scope.templates, { name: 'Decision Tree' });
|
|
return templates;
|
|
}).finally(function () {
|
|
state.dataIsLoading = false;
|
|
});
|
|
}
|
|
function loadDraftData() {
|
|
var metaDataPromise = metadataModel.getMetadataByType(EntityVO.TYPE_KNOWLEDGE), kaDraftPromise = knowledgeArticleModel.getDraft($scope.selectedTemplate.id, $scope.articleContext);
|
|
state.dataIsLoading = true;
|
|
return $q.all([metaDataPromise, kaDraftPromise]).then(function (result) {
|
|
metadata = result[0];
|
|
angular.extend(article, result[1]);
|
|
$scope.article.categoriesControls = _.cloneDeep(categoriesService.populateCategories($scope.article.defaultCategorization, metadata));
|
|
$scope.article.categoriesSet = _.cloneDeep(categoriesService.populateMultipleCategories($scope.article.allCategories, metadata));
|
|
draftArticle = _.cloneDeep($scope.article);
|
|
_.forEach($scope.article.content, function (content) {
|
|
if (content.snippet) {
|
|
content.snippet = _.compact(content.snippet.split('\n')).join('<br>');
|
|
}
|
|
});
|
|
}).finally(function () {
|
|
state.dataIsLoading = false;
|
|
});
|
|
}
|
|
//template selection screen
|
|
$scope.selectTemplate = function (template) {
|
|
state.isTemplateSelected = true;
|
|
$scope.selectedTemplate = _.cloneDeep(template);
|
|
};
|
|
//template details screen
|
|
$scope.backToTemplateSelection = function () {
|
|
$scope.selectedTemplate = null;
|
|
state.isTemplateSelected = false;
|
|
state.rememberTemplate = false;
|
|
};
|
|
$scope.acceptTemplate = function () {
|
|
loadDraftData().then(function () {
|
|
setDefaultTemplate(state.rememberTemplate ? $scope.selectedTemplate.id : null);
|
|
state.isTemplateAccepted = true;
|
|
});
|
|
};
|
|
$scope.mergeAndAcceptTemplate = function () {
|
|
var newContent = '', previousArticle = _.cloneDeep(article);
|
|
runMergeForChangeTemplate()
|
|
.then(function (content) {
|
|
$scope.previousTemplate = null;
|
|
newContent = content;
|
|
state.dataIsLoading = true;
|
|
return knowledgeArticleModel.getDraft($scope.selectedTemplate.id);
|
|
})
|
|
.then(function (result) {
|
|
angular.extend(article, knowledgeArticleModel.mergeArticleMetaData(result, previousArticle, newContent));
|
|
setDefaultTemplate(state.rememberTemplate ? $scope.selectedTemplate.id : null);
|
|
state.isTemplateAccepted = true;
|
|
}).finally(function () {
|
|
state.dataIsLoading = false;
|
|
});
|
|
};
|
|
function setDefaultTemplate(templateId) {
|
|
state.rememberTemplate = false;
|
|
localStorageService.set(localStorageDefaultTemplateKey, {
|
|
templateId: templateId,
|
|
user: currentUserId
|
|
});
|
|
}
|
|
function runMergeForChangeTemplate() {
|
|
return openMergeTool({
|
|
input: $scope.article.content,
|
|
output: _.cloneDeep($scope.selectedTemplate.templateObject.sections),
|
|
outputTitle: ['create.knowledge.merge.change.output.title'],
|
|
inputTitle: ['create.knowledge.merge.change.input.title.first', 'create.knowledge.merge.change.input.title.second']
|
|
}).then(function (content) {
|
|
return content;
|
|
});
|
|
}
|
|
//knowledge article edit screen
|
|
$scope.changeTemplate = function () {
|
|
state.isTemplateSelected = false;
|
|
state.isTemplateAccepted = false;
|
|
$scope.previousTemplate = _.cloneDeep($scope.selectedTemplate);
|
|
setDefaultTemplate(null);
|
|
loadAvailableTemplates();
|
|
};
|
|
$scope.clearTitle = function () {
|
|
$scope.article.title = '';
|
|
$scope.onKnowledgeTitleChange();
|
|
};
|
|
$scope.onKnowledgeTitleChange = function (value) {
|
|
state.similarArticles = [];
|
|
state.loadingSimilarArticles = false;
|
|
if (knowledgeTitleChangeTimer) {
|
|
$timeout.cancel(knowledgeTitleChangeTimer);
|
|
}
|
|
if (value && value.length >= 3) {
|
|
knowledgeTitleChangeTimer = $timeout(function () {
|
|
state.loadingSimilarArticles = true;
|
|
if (state.similarArticlePromise) {
|
|
state.similarArticlePromise.finally(function () {
|
|
state.loadingSimilarArticles = true;
|
|
state.similarArticles = [];
|
|
});
|
|
}
|
|
state.similarArticlePromise = knowledgeArticleModel.findArticleByText({ search_text: value }).then(function (articles) {
|
|
state.similarArticles = articles;
|
|
_.remove(state.similarArticles, { templateName: 'Decision Tree' }); //Currently not supporting decision tree
|
|
}).finally(function () {
|
|
state.loadingSimilarArticles = false;
|
|
});
|
|
}, 1000);
|
|
}
|
|
};
|
|
$scope.mergeSimilarArticle = function (id) {
|
|
state.dataIsLoading = true;
|
|
knowledgeArticleModel.getKnowledgeArticleById(id).then(function (data) {
|
|
state.dataIsLoading = false;
|
|
state.showingMergeTool = true;
|
|
return openMergeTool({
|
|
input: data.content,
|
|
output: _.cloneDeep(article.content),
|
|
outputTitle: ['create.knowledge.merge.output.title'],
|
|
inputTitle: ['create.knowledge.merge.input.title.first', 'create.knowledge.merge.input.title.second']
|
|
});
|
|
}).then(function (content) {
|
|
article.content = content;
|
|
}).finally(function () {
|
|
state.showingMergeTool = false;
|
|
});
|
|
};
|
|
$scope.updateSimilarArticle = function (id) {
|
|
state.dataIsLoading = true;
|
|
knowledgeArticleModel.getKnowledgeArticleById(id).then(function (data) {
|
|
state.dataIsLoading = false;
|
|
if (data.accessMappings.detailsEditAllowed) {
|
|
state.showingMergeTool = true;
|
|
return openMergeTool({
|
|
input: _.cloneDeep(article.content),
|
|
output: _.cloneDeep(data.content),
|
|
outputTitle: ['create.knowledge.merge.instead.output.title'],
|
|
inputTitle: ['create.knowledge.merge.instead.input.title.first', 'create.knowledge.merge.instead.input.title.second']
|
|
});
|
|
}
|
|
else {
|
|
systemAlertService.info({
|
|
text: $filter('i18n')('create.knowledge.similar.edit.instead.deny')
|
|
});
|
|
return $q.reject();
|
|
}
|
|
}).then(function (content) {
|
|
openArticleForEdit(id, content);
|
|
}).finally(function () {
|
|
state.showingMergeTool = false;
|
|
});
|
|
};
|
|
function openArticleForEdit(id, content) {
|
|
state.allowStateChange = true;
|
|
$state.go('knowledge', { id: id, content: content, editMode: true });
|
|
}
|
|
function openMergeTool(mergeParams) {
|
|
var parentScope = $scope;
|
|
return $modal.open({
|
|
templateUrl: 'views/knowledge-article/article-merge-tool.html',
|
|
controller: ['$scope', '$modalInstance', 'mergeParams',
|
|
function ($scope, $modalInstance, mergeParams) {
|
|
$scope.input = { content: mergeParams.input };
|
|
$scope.output = { content: mergeParams.output };
|
|
$scope.outputTitle = mergeParams.outputTitle || [];
|
|
$scope.inputTitle = mergeParams.inputTitle || [];
|
|
$scope.merge = function () {
|
|
$modalInstance.close($scope.output.content);
|
|
};
|
|
parentScope.$on('$destroy', $modalInstance.close);
|
|
}
|
|
],
|
|
windowClass: 'modal_article-merge-tool',
|
|
backdrop: false,
|
|
keyboard: false,
|
|
resolve: {
|
|
mergeParams: function () {
|
|
return mergeParams;
|
|
}
|
|
}
|
|
}).result;
|
|
}
|
|
$scope.handleFileChange = function (fileInput) {
|
|
var newAttachment = attachmentService.prepareFileToUpload({ fileInput: fileInput });
|
|
if (newAttachment && newAttachment.size <= 0) {
|
|
systemAlertService.warning({
|
|
text: $filter('i18n')('attachment.file_empty'),
|
|
icon: 'icon-exclamation_triangle',
|
|
clear: true,
|
|
hide: 5000
|
|
});
|
|
return;
|
|
}
|
|
if (newAttachment) {
|
|
$scope.attachments ? $scope.attachments.push(newAttachment) : $scope.attachments = [newAttachment];
|
|
}
|
|
};
|
|
$scope.dismissAttachment = function ($e, attachment) {
|
|
var index = $scope.attachments.indexOf(attachment);
|
|
if (index >= 0) {
|
|
$scope.attachments.splice(index, 1);
|
|
}
|
|
$e.stopImmediatePropagation();
|
|
};
|
|
$scope.addLinkedItem = function ($event) {
|
|
var modalInstance = $modal.open({
|
|
templateUrl: 'views/ticket/link-item-action-blade.html',
|
|
windowClass: 'action-blade',
|
|
controller: 'LinkController',
|
|
resolve: {
|
|
linkParams: function () {
|
|
return {
|
|
selectedItems: [{
|
|
id: null,
|
|
type: EntityVO.TYPE_KNOWLEDGE
|
|
}],
|
|
isDraft: true
|
|
};
|
|
}
|
|
}
|
|
});
|
|
modalInstance.result.then(function (linkedItems) {
|
|
Array.prototype.push.apply($scope.linkedItems, linkedItems);
|
|
}).finally(function () {
|
|
$event.currentTarget.focus();
|
|
});
|
|
};
|
|
$scope.removeLinkedItem = function (item) {
|
|
_.pull($scope.linkedItems, item);
|
|
};
|
|
$scope.createArticle = function () {
|
|
var createdArticle;
|
|
$scope.state.dataIsLoading = true;
|
|
$scope.article.allCategories = categoriesService.collectValues($scope.article.categoriesSet, $scope.article);
|
|
saveSetOfVisibilityGroups(article.articleVisibilityGroup);
|
|
article.title = article.title.replace(/\u00a0/g, ' ');
|
|
article.parentTicketType = ticketModel.articleParent ? ticketModel.articleParent.type : '';
|
|
setTimeout(function () {
|
|
knowledgeArticleModel.createArticle(currentUserId, article).then(function (result) {
|
|
createdArticle = result;
|
|
if (ticketModel.articleParent) {
|
|
delete ticketModel.articleParent;
|
|
}
|
|
}).then(function () {
|
|
var linkingPromise = $scope.linkedItems.length ? linkItems(createdArticle) : $q.when(1), attachmentPromise = $scope.attachments.length ? addAttachments(createdArticle) : $q.when(1);
|
|
knowledgeArticleModel.getArticleRevisionsById(createdArticle.id); //just to preload revisions, so user wont wait for them on article detail page.
|
|
return $q.all([linkingPromise, attachmentPromise]);
|
|
}).then(function () {
|
|
$scope.onCreateArticleCompleted(createdArticle);
|
|
}).catch(function (error) {
|
|
systemAlertService.error({
|
|
text: (error.data.defaultMessage) || (error.data.errorCode ? $filter('i18n')('error.unknown') : error.data.error)
|
|
});
|
|
}).finally(function () {
|
|
$scope.state.dataIsLoading = false;
|
|
});
|
|
}, 200);
|
|
};
|
|
function saveSetOfVisibilityGroups(visibilities) {
|
|
localStorageService.set(localStorageLastVisibilitySetKey, visibilities);
|
|
}
|
|
function linkItems(createdArticle) {
|
|
return relationModel.addRelation({
|
|
uuid: createdArticle.id,
|
|
type: EntityVO.TYPE_KNOWLEDGE
|
|
}, _.map($scope.linkedItems, function (item) {
|
|
return _.omit(item, ['realObject', 'isPoi']);
|
|
}));
|
|
}
|
|
function addAttachments(createdArticle) {
|
|
return attachmentService.uploadAttachment(createdArticle.type, createdArticle.id, $scope.attachments);
|
|
}
|
|
$scope.onCreateArticleCompleted = function (createdArticle) {
|
|
state.allowStateChange = true;
|
|
$state.go('knowledge', { id: createdArticle.id });
|
|
};
|
|
$scope.cancel = function () {
|
|
if ($scope.previousTemplate) {
|
|
state.isTemplateSelected = true;
|
|
state.isTemplateAccepted = true;
|
|
$scope.selectedTemplate = _.cloneDeep($scope.previousTemplate);
|
|
$scope.previousTemplate = null;
|
|
}
|
|
else {
|
|
//trick to avoid triggering $stateChangeStart event
|
|
$state.go('dashboard', {}, { notify: false }).then(function () {
|
|
$scope.$emit('$stateChangeSuccess');
|
|
});
|
|
}
|
|
};
|
|
$scope.discard = function () {
|
|
showLeaveCreateKnowledgeArticleDialog().then(function (result) {
|
|
result && $scope.cancel();
|
|
});
|
|
};
|
|
function showLeaveCreateKnowledgeArticleDialog() {
|
|
var modal = systemAlertService.modal({
|
|
type: 'info',
|
|
title: $filter('i18n')('common.notification.dirty.title'),
|
|
text: $filter('i18n')('common.notification.dirty.loseChanges'),
|
|
buttons: [
|
|
{
|
|
text: $filter('i18n')('common.button.yes'),
|
|
data: true
|
|
},
|
|
{
|
|
text: $filter('i18n')('common.button.no'),
|
|
data: false
|
|
}
|
|
]
|
|
});
|
|
return modal.result;
|
|
}
|
|
function isArticleDirty() {
|
|
return isArticleTitleDirty() || isArticleContentDirty() || isArticleMetadataDirty();
|
|
}
|
|
function isArticleContentDirty() {
|
|
var rawContent = getRawArticleContent();
|
|
return !angular.equals(draftArticle.content, rawContent);
|
|
}
|
|
function isArticleTitleDirty() {
|
|
return article.title && article.title.trim();
|
|
}
|
|
function isArticleMetadataDirty() {
|
|
var articleMetadata = _.omit(article, ['categoriesControls', 'content', 'title']), draftArticleMetadata = _.omit(article, ['categoriesControls', 'content', 'title']);
|
|
return !angular.equals(articleMetadata, draftArticleMetadata);
|
|
}
|
|
function getRawArticleContent() {
|
|
var articleContentCopy = _.cloneDeep(article.content);
|
|
return _.map(articleContentCopy, function (section) {
|
|
section.snippet = $(section.snippet).text();
|
|
return section;
|
|
});
|
|
}
|
|
$scope.state = state;
|
|
$scope.article = article;
|
|
$scope.searchService = searchService;
|
|
$scope.$on('$stateChangeStart', function (event, toState, toParams) {
|
|
if (!state.allowStateChange && state.isTemplateSelected && state.isTemplateAccepted && isArticleDirty()) {
|
|
event.preventDefault();
|
|
showLeaveCreateKnowledgeArticleDialog().then(function (result) {
|
|
if (result) {
|
|
state.allowStateChange = true;
|
|
$state.go(toState.name, toParams);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
])
|
|
.controller('CreateKnowledgeArticleModalController', ['$scope', '$controller', '$modalInstance', 'ticketModel',
|
|
function ($scope, $controller, $modalInstance, ticketModel) {
|
|
function initArticleContext() {
|
|
if (ticketModel.articleParent.type === EntityVO.TYPE_PROBLEM ||
|
|
ticketModel.articleParent.type === EntityVO.TYPE_KNOWNERROR ||
|
|
ticketModel.articleParent.type === EntityVO.TYPE_INCIDENT ||
|
|
ticketModel.articleParent.type === EntityVO.TYPE_WORKORDER) {
|
|
$scope.articleContext = {
|
|
id: ticketModel.articleParent.id,
|
|
type: ticketModel.articleParent.type
|
|
};
|
|
}
|
|
}
|
|
initArticleContext();
|
|
$.extend(this, $controller('CreateKnowledgeArticleController', { $scope: $scope }));
|
|
$scope.onCreateArticleCompleted = function (createdArticle) {
|
|
$modalInstance.close(createdArticle);
|
|
};
|
|
$scope.cancel = function () {
|
|
$modalInstance.dismiss();
|
|
};
|
|
$scope.$on('$stateChangeSuccess', $modalInstance.dismiss);
|
|
}
|
|
]);
|
|
})();
|