"use strict"; /** * Created by viktor.shevchenko on 7/21/15. */ angular.module('resourceModule') .directive('rsKaSearch', ['ticketService', 'ticketModel', '$state', 'metadataModel', '$q', 'knowledgeArticleModel', 'relationModel', 'categoriesService', '$modal', 'permissionModel', 'roles', '$filter', function (ticketService, ticketModel, $state, metadataModel, $q, knowledgeArticleModel, relationModel, categoriesService, $modal, permissionModel, roles, $filter) { return { require: '^rs', restrict: 'E', replace: true, templateUrl: 'views/resource/rs-ka-search.html', link: function (scope, element, attrs, rsController) { angular.extend(scope, rsController); var state = { processing: false, searching: false, searchNotFound: false, watcherOn: false, optionIsCollapsed: true, canCreateKnowledge: permissionModel.hasPermission(roles.ITSM_KNOWLEDGE_USER_ROLE) && !scope.context.isDraft && scope.context.accessMappings.relationsEditAllowed }, searchItems = []; scope.articlePlaceholder = { type: EntityVO.TYPE_KNOWLEDGE, allCategories: [], customer: {}, summary: '', allCompanies: [] }; scope.titleRegExp = new RegExp(/.{1,5}/g); if (scope.context.type === EntityVO.TYPE_SMARTRECORDER) { scope.articlePlaceholder.customer.company = { name: scope.context.company }; } else if (scope.context.type === EntityVO.TYPE_PROBLEM || scope.context.type === EntityVO.TYPE_KNOWNERROR) { scope.articlePlaceholder.customer.company = scope.context.company; } else if (scope.context.customer && scope.context.customer.company) { scope.articlePlaceholder.customer.company = scope.context.customer.company; } else { scope.articlePlaceholder.customer.company = scope.context.customer || scope.context.company; } scope.contextRelations = relationModel.cache[scope.context.id]; if (scope.context.type === EntityVO.TYPE_KNOWLEDGE) { scope.articlePlaceholder.allCompanies = scope.context.allCompanies; //SW00512025 - passing All even if its not a selected company for this KA if (!_.find(scope.articlePlaceholder.allCompanies, { name: 'All' })) { scope.articlePlaceholder.allCompanies.push({ name: 'All' }); } } else { scope.articlePlaceholder.allCompanies.push({ name: 'All' }); scope.articlePlaceholder.allCompanies.push(scope.articlePlaceholder.customer.company); } scope.toggleOptions = function () { state.optionIsCollapsed = !state.optionIsCollapsed; }; scope.createNewArticle = function () { ticketModel.articleParent = scope.context; var modalInstance = $modal.open({ templateUrl: 'views/create/create-ka.html', controller: 'CreateKnowledgeArticleModalController', windowClass: 'modal_full-content', backdrop: false, keyboard: false }); modalInstance.result.then(function (article) { var newResource = new RelationItemVO().build({ id: article.id, displayId: article.articleId, title: article.title, desc: article.title, type: article.type, additionalInformation: { modifiedDate: article.modifiedDate }, tag: EntityVO.TYPE_RESOURCE, relationshipType: EntityVO.TYPE_RELATEDTO, realObject: { status: article.status, version: article.version, modifiedDate: article.modifiedDate } }); scope.saveToTicket(newResource).then(function () { $state.go(newResource.type, { id: newResource.id, }); }); scope.toggleSearchKa(); }); }; scope.setSortOption = function (option) { scope.selectedSortOption = option; scope.searchArticle(); }; scope.changeStatusOption = function (status) { scope.statusOptions = status; }; scope.changeSourceOption = function (source) { scope.sourceOptions = source; }; scope.searchArticle = function () { if (state.searching) { return; } state.searching = true; scope.searchResults = []; state.searchNotFound = false; knowledgeArticleModel.clearVisitedArticlesForTicket(scope.context.id); var searchData = { search_text: scope.articlePlaceholder.summary, suggest_search: true, chunk_index: 0, chunk_size: 15 }, searchOptions = {}, categoryList = scope.articlePlaceholder.allCategories; if (scope.statusOptions) { searchOptions.statuses = [{ value: scope.statusOptions.name }]; } if (scope.sourceOptions) { searchOptions.source = scope.sourceOptions.name; } searchOptions.category = []; _.each(categoryList, function (category) { if (category.listOfTiers[0] && category.listOfTiers[0].selectedValue) { var categoryData = {}; categoryData.name = category.name; categoryData.tiers = {}; _.each(category.listOfTiers, function (tier) { categoryData.tiers[tier.name] = tier.selectedValue ? tier.selectedValue : ''; }); searchOptions.category.push(categoryData); } }); findArticles(searchData, searchOptions); scope.searchData = searchData; scope.searchOptions = searchOptions; !state.watcherOn && initWatch(); }; function findArticles(searchData, searchOptions) { knowledgeArticleModel.findArticleByText(searchData, searchOptions, scope.selectedSortOption).then(function (articles) { searchItems = _.filter(articles, function (article) { return scope.context.id !== article.id; }); populateArticles(scope.contextRelations); }).finally(function () { state.searching = false; }); } function populateArticles(relatedItems) { if (!searchItems || !searchItems.length) { state.searchNotFound = true; return; } var relatedArticles = _.filter(relatedItems, function (relatedItem) { return _.find(searchItems, { id: relatedItem.id }); }), notRelatedArticles = _.reject(searchItems, function (searchItem) { return _.find(relatedArticles, { id: searchItem.id }); }); scope.searchResults = relatedArticles.concat(notRelatedArticles); if (scope.context.type !== EntityVO.TYPE_KNOWLEDGE) { checkForVisitedArticles(scope.searchResults); } } function initWatch() { scope.$watchCollection('contextRelations', function (relatedItems) { if (!state.watcherOn) { state.watcherOn = true; return; //Code below shouldn't run when initializing the watch } if (relationModel.unlinked.length && rsController.isKaSearchEnabled()) { //Case : Article is unlinked and advanced search articles screen relationModel.unlinked.length = 0; findArticles(scope.searchData, scope.searchOptions); return; } populateArticles(relatedItems); }, true); } scope.clearSearch = function () { scope.articlePlaceholder.summary = ''; scope.searchResults = []; searchItems.length = 0; state.searchNotFound = false; }; //Knowledge status is not getting populated when using filter in html in case of browser refresh because metadataModel.cache doesn't fetch value at that time. scope.localizedStatus = function (status) { return $filter('localizeLabel')(status, 'status', 'knowledge'); }; function checkForVisitedArticles(searchResults) { var visitedArticlesList = knowledgeArticleModel.getVisitedArticlesForTicket(scope.context.id); searchResults.some(function (article) { article.visited = false; return article instanceof GlobalSearchItemVO; //RelationItemVO are taken from cache so marking only them false. }); if (!_.isEmpty(visitedArticlesList)) { _.forEach(searchResults, function (article) { article.visited = _.includes(visitedArticlesList, article.id); }); } } function init() { scope.clearSearch(); scope.state = state; scope.itemsLimit = 4; scope.sortOptions = [ { name: 'mostRelevant', sortFieldName: '', sortFieldOrder: '' }, { name: 'mostFavorite', sortFieldName: 'favorite', sortFieldOrder: 'des' }, { name: 'mostRecent', sortFieldName: 'modifiedDate', sortFieldOrder: 'des' } ]; scope.selectedSortOption = scope.sortOptions[0]; state.processing = true; $q.all([metadataModel.getMetadataByType(EntityVO.TYPE_KNOWLEDGE), knowledgeArticleModel.getKnowledgeArticleTemplates()]) .then(function (result) { var metaData = result[0]; var categorizations = [ { name: 'operational', tiers: {} }, { name: 'product', tiers: {} } ]; scope.availableStatuses = metaData.statuses ? metaData.statuses.slice() : []; // remove work in progress status since it is not supported by backend MTF search _.remove(scope.availableStatuses, { name: 'Work In Progress' }); scope.articlePlaceholder.allCategories = _.cloneDeep(categoriesService.populateCategories(categorizations, metaData)); scope.availableSources = result[1]; }) .finally(function () { state.processing = false; }); } init(); } }; } ]);