"use strict"; /** * Created by igor.samulenko on 4/29/2014. */ (function () { 'use strict'; angular.module('adminModule') .factory('screenConfigurationModel', ['$q', 'screenConfigurationService', 'configurationModel', 'i18nService', function ($q, screenConfigurationService, configurationModel, i18nService) { var screenConfigurationModel = { appConfig: null, screenList: null, screensCacheByName: {}, fieldList: null, fieldLabels: null, selectedFieldList: null, actionList: null, actionOrder: 'custom', actionUrlParams: null, availableFieldsCache: {}, runtimeActionsCache: {}, dynamicSelectionFieldLabelsCache: {}, providerPromise: {}, providerHardReload: true }, customLabelPromise = null, configByNamePromise = null, fieldLabelDictionary = {}, screenTypeMap = { incident: ScreenConfigurationVO.prototype.INCIDENT_VIEW_SCREEN, workorder: ScreenConfigurationVO.prototype.WORK_ORDER_VIEW_SCREEN, task: ScreenConfigurationVO.prototype.TASK_VIEW_SCREEN, person: ScreenConfigurationVO.prototype.PERSON_DETAILS_SCREEN, change: ScreenConfigurationVO.prototype.CHANGE_VIEW_SCREEN, problem: ScreenConfigurationVO.prototype.PROBLEM_DETAILS_SCREEN, knownerror: ScreenConfigurationVO.prototype.KNOWN_ERROR_DETAILS_SCREEN, asset: ScreenConfigurationVO.prototype.ASSET_SCREEN, create: { incident: ScreenConfigurationVO.prototype.CREATE_INCIDENT_SCREEN, change: ScreenConfigurationVO.prototype.CREATE_CHANGE_SCREEN, workorder: ScreenConfigurationVO.prototype.CREATE_WORK_ORDER_SCREEN, task: ScreenConfigurationVO.prototype.CREATE_TASK_SCREEN } }; // editor actions var ACTION_CREATE = 'create', ACTION_UPDATE = 'update', ACTION_REMOVE = 'remove'; /** * Public functions */ /** * Loads screen configuration */ var screenConfigurationPromise = $q.defer(); screenConfigurationModel.loadConfiguration = function () { screenConfigurationModel.appConfig = {}; screenConfigurationModel.screenList = []; // Using fromConfig flag, required by backend since this call is used // only on screen configuration return screenConfigurationService.loadConfiguration({ fromConfig: true }) .then(handleConfigurationLoadSuccess); }; /** * Get screen configuration for specific screen by name * @param {string} screenName - name of the screen to load * @param {boolean} force - if true, will enforce request for screen configuration to be sent * @param {object} options - additional request params * @return {Promise} */ screenConfigurationModel.loadScreenConfigurationByName = function (screenName, force, options) { var cachedScreen = force ? angular.noop() : getScreenByName(screenName), screenPromise; if (cachedScreen) { screenPromise = $q.when(cachedScreen); } else { if (configByNamePromise === null) { configByNamePromise = screenConfigurationService.loadScreenConfigurationByName(screenName, options) .then(function (screenConfig) { screenConfigurationModel.screensCacheByName[screenName] = screenConfig.screens[0]; screenConfigurationModel.screenList = Object.keys(screenConfigurationModel.screensCacheByName) .map(function (key) { return screenConfigurationModel.screensCacheByName[key]; }); configByNamePromise = null; return angular.copy(screenConfigurationModel.screensCacheByName[screenName]); }); } screenPromise = configByNamePromise; } return screenPromise; }; screenConfigurationModel.loadScreenConfigurationAndCustomFieldLabels = function (screenName, ticketType, force) { var deferred = $q.defer(); screenConfigurationModel.loadScreenConfigurationByName(screenName, force) .then(function () { return screenConfigurationModel.loadFieldsLabels(ticketType); }) .finally(function () { deferred.resolve(); }); return deferred.promise; }; /** * Refreshes metadata for specific datasource * * @param {String} datasource * @param {String} screenName - optional parameter, used for screens that support v2 calls only * @returns {*} */ screenConfigurationModel.refreshMetadataForDatasource = function (datasource, screenName) { var params = { datasource: datasource }; if (screenName) { params.screen = screenName; } var refreshMeta = function () { if (fieldLabelDictionary[datasource]) { delete fieldLabelDictionary[datasource]; } }; if (screenConfigurationModel.isV2CompatibleScreen(screenName)) { return screenConfigurationService.refreshMetadataV2(params).then(refreshMeta); } else { return screenConfigurationService.refreshMetadata(params).then(refreshMeta); } }; /** * Loads field data required for custom area editor * @param panel * @returns {*} */ screenConfigurationModel.loadFields = function (panel) { var availableFieldListPromise = screenConfigurationModel.loadAvailableFieldList(panel), selectedFieldListPromise = screenConfigurationModel.loadSelectedFieldList(panel); return $q.all([availableFieldListPromise, selectedFieldListPromise]); }; /** * Loads list of fields available for selection * @param {PanelVO} panel */ screenConfigurationModel.loadAvailableFieldList = function (panel) { var query = { datasource: panel.dataSource }, promise; if (panel.dataSource === 'Asset') { query.assetType = panel.shortId; if (panel.shortId === 'typeSpecific') { query.classId = panel.classId; } } if (screenConfigurationModel.isV2CompatibleScreen(panel.parentScreenName)) { query.screen = panel.parentScreenName; promise = screenConfigurationService.loadAvailableFieldListV2(query); } else { promise = screenConfigurationService.loadAvailableFieldList(query); } return promise.then(handleAvailableFieldListLoadSuccess); }; /** * Loads available fields list for four new screens introduced in v2.0. * @returns {Array} - list of */ screenConfigurationModel.loadAvailableFieldListForAllNewScreens = function (force) { var screensData = []; if (configurationModel.isServerApplicationEnabled(EntityVO.TYPE_INCIDENT)) { screensData.push({ datasource: EntityVO.TYPE_INCIDENT, screen: ScreenConfigurationVO.prototype.INCIDENT_VIEW_SCREEN }, { datasource: EntityVO.TYPE_INCIDENT, screen: ScreenConfigurationVO.prototype.CREATE_INCIDENT_SCREEN }); } if (configurationModel.isServerApplicationEnabled(EntityVO.TYPE_CHANGE)) { screensData.push({ datasource: EntityVO.TYPE_CHANGE, screen: ScreenConfigurationVO.prototype.CHANGE_VIEW_SCREEN }, { datasource: EntityVO.TYPE_CHANGE, screen: ScreenConfigurationVO.prototype.CREATE_CHANGE_SCREEN }); } if (configurationModel.isServerApplicationEnabled(EntityVO.TYPE_WORKORDER)) { screensData.push({ datasource: EntityVO.TYPE_WORKORDER, screen: ScreenConfigurationVO.prototype.WORK_ORDER_VIEW_SCREEN }, { datasource: EntityVO.TYPE_WORKORDER, screen: ScreenConfigurationVO.prototype.CREATE_WORK_ORDER_SCREEN }); } if (configurationModel.isServerApplicationEnabled(EntityVO.TYPE_TASK)) { screensData.push({ datasource: EntityVO.TYPE_TASK, screen: ScreenConfigurationVO.prototype.TASK_VIEW_SCREEN }, { datasource: EntityVO.TYPE_TASK, screen: ScreenConfigurationVO.prototype.CREATE_TASK_SCREEN }); } var promises = {}; if (force) { screensData.forEach(function (screenData) { promises[screenData.screen] = screenConfigurationService.loadAvailableFieldListV2(screenData) .then(function (availableFields) { screenConfigurationModel.availableFieldsCache[screenData.screen] = availableFields; }); }); } else { promises = [$q.when(screenConfigurationModel.availableFieldsCache)]; } return $q.all(promises).then(function () { return angular.copy(screenConfigurationModel.availableFieldsCache); }); }; /** * Loads Actions and Url params w.r.t to resource * @param resourceType */ screenConfigurationModel.loadActions = function (resourceType) { return screenConfigurationService.loadActions({ resourceType: resourceType }).then(handleActionsLoadSuccess); }; screenConfigurationModel.loadActionUrlParams = function (resourceType) { return screenConfigurationService.loadActionUrlParams({ resourceType: resourceType }).then(handleActionUrlParamsLoadSuccess); }; /** * Loads Actions V2 and Url params w.r.t to resource * @param resourceType */ screenConfigurationModel.loadActionsNew = function (resourceType) { if (!screenConfigurationModel.providerPromise[resourceType] || screenConfigurationModel.providerHardReload) { screenConfigurationModel.providerPromise[resourceType] = screenConfigurationService.loadActionsNew({ resourceType: resourceType }).then(handleActionsLoadSuccess); screenConfigurationModel.providerHardReload = false; return screenConfigurationModel.providerPromise[resourceType]; } else { return screenConfigurationModel.providerPromise[resourceType]; } }; /** * Loads list of selected fields * @param {PanelVO} panel */ screenConfigurationModel.loadSelectedFieldList = function (panel) { var query = { datasource: panel.dataSource }; if (panel.dataSource === 'Asset') { query.assetType = panel.shortId; if (panel.shortId === 'typeSpecific') { query.classId = panel.classId; } } return screenConfigurationService.loadSelectedFieldList(query).then(handleSelectedFieldListLoadSuccess); }; /** * Loads fields labels * @param {String} ticketType */ screenConfigurationModel.loadFieldsLabels = function (ticketType) { var editTicketScreenName = screenTypeMap[ticketType], createTicketScreenName = screenTypeMap.create[ticketType]; var screen = _.find(screenConfigurationModel.screensCacheByName, function (scr) { return [editTicketScreenName, createTicketScreenName].indexOf((scr || {}).name) !== -1; }); var promise = $q.when(1); if (screen) { var dataSource = screen.datasource, cachedLabels = fieldLabelDictionary[dataSource]; if (cachedLabels) { handleFieldLabelsLoadSuccess(cachedLabels, dataSource); } else { if (customLabelPromise === null) { customLabelPromise = screenConfigurationService .loadFieldsLabels({ datasource: dataSource }) .then(function (labels) { handleFieldLabelsLoadSuccess(labels, dataSource); customLabelPromise = null; return screenConfigurationModel.fieldLabels; }); } promise = customLabelPromise; } } else { console.log('Warning: screen configuration for ' + ticketType + ' not found.'); } return promise; }; screenConfigurationModel.loadMockDependantFieldMappings = function () { return screenConfigurationService.loadMockDependantFieldMappings(); }; /** * Loads fields labels * @param {String} ticketType * @param {String} menuName * @param {Object} params * @param {Object} dependencies */ screenConfigurationModel.loadDynamicSelectionFieldLabels = function (ticketType, menuName, searchText, dependencies, classId, fieldName, isNew, useChunk) { var screen = getScreenForTicketType(isNew ? ('create.' + ticketType) : ticketType), params = { datasource: screen ? screen.datasource : ticketType, menuName: menuName, searchText: searchText }; function escapeRegExp(string) { return string.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); } if (classId) { params.classId = classId; } if (screen) { var dynamicFieldCache = screenConfigurationModel.dynamicSelectionFieldLabelsCache[fieldName]; if (!useChunk && angular.isDefined(dynamicFieldCache) && _.startsWith(searchText, dynamicFieldCache.searchText)) { if (dynamicFieldCache.datasource === params.datasource && _.isEqual(dependencies, dynamicFieldCache.dependencies)) { var searchData = _.cloneDeep(dynamicFieldCache.searchData), escaped = escapeRegExp(searchText), formatted = escaped.replace(/%/g, '.*'); formatted = '.*' + formatted + '.*'; formatted = new RegExp('^' + formatted + '$', 'im'); _.remove(searchData, function (field) { //To support search using wildcard '%' also. if (!field.displayLabel.match(formatted) && !field.value.match(formatted)) { return true; } }); return $q.when(searchData); } } return screenConfigurationService.loadDynamicSelectionFieldLabels(params, dependencies).then(function (data) { screenConfigurationModel.dynamicSelectionFieldLabelsCache[fieldName] = { searchText: searchText, searchData: data, datasource: params.datasource, dependencies: dependencies }; return { items: data.items, exceedsChunkSize: data.exceedsChunkSize }; }); } else { console.log('Warning: screen configuration for ' + ticketType + ' not found.'); return $q.reject(); } }; /** * Helper method, which marks fields as updated. Used for v2 customization save call * @param {FieldVO} field * @param {PanelVO} panel */ screenConfigurationModel.markFieldUpdated = function (field, panel) { var isNewField = !field.id || panel.addedFields.some(function (aField) { return field.id === aField.id; }); if (!isNewField) { field.wasUpdated = true; } }; /** * Checks whether particular screen supports v2 res calls * * @param {string} screenName - name of the screen * @returns {boolean} */ screenConfigurationModel.isV2CompatibleScreen = function (screenName) { return ScreenConfigurationVO.prototype.isV2Compatible(screenName); }; /** * Saves custom field configuration for panel * @param {PanelVO} panel */ screenConfigurationModel.savePanelConfiguration = function (panel) { var updatedFields = [], addedFields = [], removedFields = [], useV2Flow = screenConfigurationModel.isV2CompatibleScreen(panel.parentScreenName); if (useV2Flow) { var fields = getPanelUpdatedFieldsForV2Call(panel); fields.forEach(function (field) { addUpdatedField(field, panel); }); } else { // update field ordering panel.fields.forEach(function (field, index) { var members = []; field.displayOrder = index; field.groupMember = false; if (field.dependency) { for (var j = 0; j < field.dependency.length; j++) { delete field.dependency[j].availability; delete field.dependency[j].fieldUnavailableOn; } } // Handle group fields, but skip this if field is a widget if (!field.isWidget()) { field.members.forEach(function (gfield, gindex) { var temp = { "name": gfield.name }; gfield.displayOrder = gindex; gfield.groupMember = true; if (gfield.dependency) { for (var j = 0; j < gfield.dependency.length; j++) { delete gfield.dependency[j].availability; delete gfield.dependency[j].fieldUnavailableOn; } } if (gfield.id) { addUpdatedField(gfield, panel); if (gfield.current) { temp = gfield.current; } } members.push(temp); }); field.members = members; } if (field.id) { addUpdatedField(field, panel); } }); } function addUpdatedField(field, panel) { if (panel.shortId !== 'typeSpecific') { delete field.extension; } if (useV2Flow) { updatedFields.push(angular.extend({ state: ACTION_UPDATE, screenId: panel.parentScreenId, screenName: panel.parentScreenName, panelId: panel.id, panelName: panel.name, datasource: panel.dataSource }, new GalileoFieldV2VO().build(field))); } else { updatedFields.push(angular.extend({ state: ACTION_UPDATE, areaId: panel.id }, new GalileoFieldVO().build(field))); } } if (useV2Flow) { addedFields = getPanelAddedFieldsForV2Call(panel); removedFields = getPanelRemovedFieldsForV2Call(panel); } else { addedFields = panel.addedFields.map(function (field) { var newField; if (panel.shortId !== 'typeSpecific') { delete field.extension; } newField = angular.extend({ state: ACTION_CREATE, areaId: panel.id }, new GalileoFieldVO().build(field)); return newField; }); removedFields = panel.removedFields.map(function (field) { var removedField; if (panel.shortId !== 'typeSpecific') { delete field.extension; } removedField = angular.extend({ state: ACTION_REMOVE, areaId: panel.id }, new GalileoFieldVO().build(field)); return removedField; }); } var saveFieldConfiguration = useV2Flow ? screenConfigurationService.saveFieldConfigurationV2 : screenConfigurationService.saveFieldConfiguration; return saveFieldConfiguration([].concat(removedFields, addedFields, updatedFields), panel.shortId) .catch(function (e) { throw e; }) .finally(function () { screenConfigurationModel.clearActionsListCacheForType(panel.dataSource.toLowerCase()); }); }; function getPanelFieldsV2Call(panel, action) { var fields = []; if (action === ACTION_CREATE) { fields = panel.addedFields; } else if (action === ACTION_REMOVE) { fields = panel.removedFields; } return fields.reduce(function (acc, field) { var fieldCopy = _.cloneDeep(field); if (field.isGroupField()) { // Should use original members list for remove action, because user can firs remove group members // manually and then remove group, so members array will be empty, which is wrong var groupMembers = (action === ACTION_REMOVE) ? field.initialMembers : field.members; fieldCopy.members = groupMembers.map(function (member) { return new GalileoFieldV2VO().build(member); }); } // Don't need to send group members separately. // Group field members array will be used on the backend if (!field.isGroupMember()) { acc.push(angular.extend({ state: action, screenId: panel.parentScreenId, screenName: panel.parentScreenName, panelId: panel.id, panelName: panel.name, datasource: panel.dataSource }, new GalileoFieldV2VO().build(fieldCopy))); } return acc; }, []); } function getPanelAddedFieldsForV2Call(panel) { return getPanelFieldsV2Call(panel, ACTION_CREATE); } function getPanelRemovedFieldsForV2Call(panel) { return getPanelFieldsV2Call(panel, ACTION_REMOVE); } function getPanelUpdatedFieldsForV2Call(panel) { return panel.fields.reduce(function (acc, field, index) { var fieldMembers = []; if (field.displayOrder !== index) { field.displayOrder = index; screenConfigurationModel.markFieldUpdated(field, panel); } if (field.dependency) { for (var j = 0; j < field.dependency.length; j++) { delete field.dependency[j].availability; delete field.dependency[j].fieldUnavailableOn; } } // Handle group fields, but skip this if field is a widget if (field.isGroupField()) { fieldMembers = field.members.map(function (gfield, gindex) { if (gfield.displayOrder !== gindex) { gfield.displayOrder = gindex; screenConfigurationModel.markFieldUpdated(gfield, panel); } if (gfield.dependency) { for (var j = 0; j < gfield.dependency.length; j++) { delete gfield.dependency[j].availability; delete gfield.dependency[j].fieldUnavailableOn; } } if (!gfield.id || gfield.wasUpdated) { screenConfigurationModel.markFieldUpdated(field, panel); } return new GalileoFieldV2VO().build(gfield); }); } if (field.id && field.wasUpdated) { var fieldCopy = _.cloneDeep(field); fieldCopy.members = fieldMembers; acc.push(fieldCopy); } return acc; }, []); } /** * Saves custom action configuration * @param {PanelVO} panel */ screenConfigurationModel.saveActionConfiguration = function (actionList, actionOrder) { var actionObj = { actionOrder: actionOrder, actionList: [] }; actionList.forEach(function (action) { delete action.isOpen; actionObj.actionList.push(action); }); return screenConfigurationService.saveActionConfiguration(actionObj).then(handleActionsLoadSuccess); }; /** + * Saves custom action configuration V2 + * @param {PanelVO} panel + */ screenConfigurationModel.saveFieldConfigurationV2 = function (actionList, actionOrder) { var actionObj = { actionOrder: actionOrder, actionList: [] }; actionList.forEach(function (action) { delete action.isOpen; actionObj.actionList.push(action); }); return screenConfigurationService.saveFieldConfigurationV2(actionObj).then(handleActionsLoadSuccess); }; /** * Finds a panel with specified name * @param {String} panelId */ screenConfigurationModel.getPanelById = function (panelId) { var screenName = panelId.split('.')[0]; var panelName = panelId.split('.')[1]; var screen = getScreenByName(screenName); return screen ? screen.getPanelByName(panelName) : null; }; /** * Get list of editable fields for screen with specified name * @param {String} screenName * @return {Array} fields */ screenConfigurationModel.getEditableFieldsForScreen = function (screenName) { var screen = getScreenByName(screenName); return _.where(screen ? screen.getFields() : [], { editable: true }); }; /** * Get list of required fields for screen with specified name * @param {String} screenName * @return {Array} fields */ screenConfigurationModel.getRequiredFieldsForScreen = function (screenName) { var screen = getScreenByName(screenName); return _.where(screen ? screen.getFields() : [], { required: true }); }; /** * Get list of available fields for screen with specified name * @param screenName * @param {Array} availableFields - optional param of available fields to build list from * @return {Array} fields */ screenConfigurationModel.getAvailableFieldsForScreen = function (screenName, availableFields) { var screen = getScreenByName(screenName); var fields = screen ? screen.getFields() : []; return (availableFields || screenConfigurationModel.fieldList).filter(function (field) { return !_.where(fields, { name: field.name, dataType: field.dataType }).length; }); }; /** * Get list of available fields for screen with specified name * @param screenName * @return {Array} fields */ screenConfigurationModel.getFieldByName = function (screenName, fieldName) { var screen = getScreenByName(screenName); var fields = screen ? screen.getFields() : []; return _.find(fields, { name: fieldName }); }; /** * Get list of available fields for screen with specified name and classId * @param screenName, classId * @return {Array} fields */ screenConfigurationModel.getAvailableFieldsForScreenByClassId = function (screenName, classId) { var screen = getScreenByName(screenName); var fields = screen ? screen.getFields() : []; return screenConfigurationModel.fieldList.filter(function (field) { var i, j; var selectedfields = _.where(fields, { name: field.name }); if (!selectedfields.length) { return true; } else { for (i = 0; i < selectedfields.length; i++) { for (j = 0; j < selectedfields[i].extension.length; j++) { if (selectedfields[i].extension[j].classId === classId.name) { return false; } } } return true; } }); }; /** * Get assignment panel descriptor * * @param ticket * @returns {ScreenConfigurationVO} */ screenConfigurationModel.getAssignmentPanel = function (ticket) { var panel; if (ticket.type) { var screen = getScreenForTicketType(ticket.type); if (screen) { panel = screen.getPanelByName('Assignment'); } } return panel || {}; }; /** * Get Avialable accelerators V2 * * @param type * @param {String} screenName - screen name for accelerators * @returns OOTB fields + avilable custom fields map */ screenConfigurationModel.getAccelerators = function (type, screenName) { var promise; // if (screenConfigurationModel.isV2CompatibleScreen(screenName) && ([ScreenConfigurationVO.prototype.WORK_ORDER_VIEW_SCREEN, ScreenConfigurationVO.prototype.TASK_VIEW_SCREEN].indexOf(screenName) === -1)) { if (screenConfigurationModel.isV2CompatibleScreen(screenName)) { promise = screenConfigurationService.getNewAcceleratorsByType({ datasource: type, screen: screenName }).then(function (data) { return data; }); } else { promise = screenConfigurationService.getAcceleratorsByType({ datasource: type }).then(function (data) { return data; }); } return promise; }; /** * Collect field value changes * * @param {Array} changedFields * @param {Object} originalFields */ screenConfigurationModel.collectChanges = function (changedFields, originalFields, ticket) { var changes = {}; _.forEach(changedFields, function (field) { var isGroupMember = field.isGroupMember(); if (field.editable || isGroupMember) { var newValue = field.getValue(), oldValue = originalFields ? originalFields[field.name] : '', valueChanged = (isValid(newValue) && (newValue !== oldValue)) || (newValue === null && isValid(oldValue) && oldValue !== ''); if (valueChanged || isGroupMember) { if (field.type === 'category') { var category = getCategoryValue(newValue); //Asset and knowledge needs to be handled separately as currently a seperate call is made to specially save //their categories (at least for assets) if (category) { if (_.find(ticket.resCategorizations, { name: category.name })) { if (changes.resCategorizations instanceof Array) { changes.resCategorizations.push(category); } else { changes.resCategorizations = [category]; } } else if (_.find(ticket.categorizations, { name: category.name })) { if (changes.categorizations instanceof Array) { changes.categorizations.push(category); } else { changes.categorizations = [category]; } } } } else if (field.dataType === 'widget') { _.forEach(field.members, function (member) { changes[member.name] = field.value[member.name]; }); } else { changes[field.name] = newValue; } if (field.isMenuField() && newValue === '') { //special handling for menu fields, they cannot be '', null or menuItem changes[field.name] = null; } if (field.linkedFieldExist()) { changes[field.valueField] = field.getLinkedValue(); } } } }); return changes; }; screenConfigurationModel.composePanelId = function (ticketType, panelName) { return screenConfigurationModel.getScreenNameByTicketType(ticketType) + '.' + panelName; }; /** * Init custom field values from ticket data * * @param {Array} fields * @param {TicketVO} ticket */ screenConfigurationModel.initFieldValues = function (fields, ticket, metadata) { var ootbMappingKey, setValuesdefer = $q.defer(), noOfFieldsSet = 0; if (fields && fields.length > 0) { var fieldValues; _.each(fields, function (field) { if ((ticket.type === 'incident' || ticket.type === 'change') && field.name === 'summary') { field.charLimit = 100; } else if (ticket.type === 'task' && field.name === 'summary') { field.charLimit = 255; } if (field.isWidget()) { field.label = i18nService.getLocalizedString('field.widget.' + field.name + '.label'); } if (field.type === FieldVO.prototype.PERSON_NAME) { var fieldName = field.name === 'requestedFor' ? 'customer' : field.name; fieldValues = ticket[fieldName]; if (field.name === "contact") { if (_.isEmpty(ticket[fieldName])) { fieldValues = undefined; } } else if (field.isAssigneeWidget()) { field.primaryKey = getOotbPrimaryKeyForWidget(field, metadata); fieldValues = ticket[field.primaryKey]; } field.setValue(fieldValues); noOfFieldsSet++; } else if (field.type === FieldVO.prototype.PRIORITY) { field.setValue({ impact: ticket.impact, urgency: ticket.urgency, priority: ticket.priority }); noOfFieldsSet++; } else if (field.type === FieldVO.prototype.TICKET_CLASS) { field.setValue({ timing: ticket.timing, timingReason: ticket.timingReason }); noOfFieldsSet++; } else if (field.type === FieldVO.prototype.AFFECTED_ASSET) { fieldValues = { 'ci': ticket[field.name], 'company': ticket.company, 'customer': ticket.customer, 'ticketType': ticket.type }; if (_.isEmpty(ticket[field.name]) || _.isEmpty(ticket[field.name].name)) { fieldValues.ci = null; } field.setValue(fieldValues); noOfFieldsSet++; } else if (field.type === FieldVO.prototype.TICKET_LOCATION) { if (ticket.location) { fieldValues = { 'siteId': ticket.location.siteId, 'region': ticket.location.region, 'siteGroup': ticket.location.siteGroup, 'name': ticket.location.name, 'companyName': ticket.location.companyName, 'address': ticket.location.address }; } else { fieldValues = { 'siteId': null, 'region': null, 'siteGroup': null, 'name': null, 'companyName': null, 'address': null }; } field.setValue(fieldValues); noOfFieldsSet++; } else if (field.type === FieldVO.prototype.IMPACTED_AREAS) { field.setValue({ impactedAreas: ticket.impactedAreas }); noOfFieldsSet++; } else if (field.type === FieldVO.prototype.CATEGORY_FIELD) { field.setValue(_.findLast(_.cloneDeep(ticket.allCategories), { name: field.getCategorizationPropertyName() })); noOfFieldsSet++; } else if (field.type === FieldVO.prototype.PERSON_SITE) { var siteInfo = _.cloneDeep(ticket.customer.site); var siteValue = { site: { name: siteInfo.name, id: siteInfo.siteId, attributeMap: { siteAddress: siteInfo.address, regionName: siteInfo.region, siteGroupName: siteInfo.siteGroup } }, siteGroup: { name: siteInfo.siteGroup, attributeMap: { regionName: siteInfo.region } }, region: { name: siteInfo.region }, company: ticket.customer.company }; field.setValue(siteValue); noOfFieldsSet++; } else if (field.type === FieldVO.prototype.PERSON_LOCATION_MAP) { field.setValue(ticket.customer.site.address); noOfFieldsSet++; } else if (field.type === FieldVO.prototype.POI_LOCATION) { field.setValue(_.cloneDeep(ticket.location)); noOfFieldsSet++; } else if (field.type === FieldVO.prototype.CATEGORY_COMPANY) { if (ticket.locationCompany && ticket.locationCompany.name) { field.setValue(ticket.locationCompany.name); } noOfFieldsSet++; } else if (field.type === FieldVO.prototype.TASK_PHASE) { if (ticket.selectedPhase) { field.setValue({ phaseGuid: ticket.selectedPhase.guid, phaseName: ticket.selectedPhase.name }); } noOfFieldsSet++; } else if (field.isSupportGroupWidget()) { field.primaryKey = getOotbPrimaryKeyForWidget(field, metadata); var supportGroup = angular.copy(ticket[field.primaryKey]); if (supportGroup) { supportGroup.supportGroups = supportGroup.name || supportGroup.supportGroups; } field.setValue(supportGroup); noOfFieldsSet++; } else if (field.isGroupField()) { screenConfigurationModel.initFieldValues(field.members, ticket, metadata); noOfFieldsSet++; } else { if (field.isWidget() && field.members.length > 0) { field.setValue(getOotbFieldValue(ticket, metadata, field)); noOfFieldsSet++; } else { if (metadata) { ootbMappingKey = metadata.ootbMapping[field.name]; } if (!field.ootb) { field.setValue(_.get(ticket.customFields, field.name)); noOfFieldsSet++; } else if (ootbMappingKey && ootbMappingKey.length > 0) { //if field is ootb field.setValue(getFieldValue(field.name, ootbMappingKey, ticket)); if (field.name === 'assignee' || field.name === 'assigneeName' || field.name === 'managerName') { var tempFieldName = ootbMappingKey[0].split('.'); field.assigneeLoginId = ticket[tempFieldName[0]] ? ticket[tempFieldName[0]].loginId : null; } noOfFieldsSet++; } else { field.setValue(ticket[field.name]); noOfFieldsSet++; } } } if (noOfFieldsSet === fields.length) { setValuesdefer.resolve(); } }); } else { setValuesdefer.resolve(); } return setValuesdefer.promise; }; /** * Update ticket data from custom field values * * @param {TicketVO} ticket * @param {Object} changes */ screenConfigurationModel.updateTicketData = function (ticket, changes) { if (_.size(changes)) { if (!ticket.customFields) { ticket.customFields = {}; } _.forOwn(changes, function (value, fieldName) { ticket.customFields[fieldName] = value; }); } }; /** * Check if all required fields are filled * @param ticket */ screenConfigurationModel.ticketDataIsValid = function (ticket) { var screenName = screenConfigurationModel.getScreenNameByTicketType(ticket.type); var requiredFields = screenConfigurationModel.getRequiredFieldsForScreen(screenName); var result = true; _.each(requiredFields, function (field) { if (!field.isCheckboxField()) { result = result && isValid(ticket.customFields[field.name]); } }); return result; }; /** * Check the number of reguired fields missing * @param ticket */ screenConfigurationModel.ticketNumOfRequiredFieldMissing = function (ticket) { var screenName = screenConfigurationModel.getScreenNameByTicketType(ticket.type); var requiredFields = screenConfigurationModel.getRequiredFieldsForScreen(screenName); var numOfRequiredFieldMissing = 0; _.each(requiredFields, function (field) { if (!isValid(ticket.customFields[field.name])) { numOfRequiredFieldMissing += 1; } }); return numOfRequiredFieldMissing; }; /** * Load actions for record for runtime menu * @param resourceType * @param refreshData */ screenConfigurationModel.loadActionsForRuntime = function (resourceType, refreshData) { return executeLoadActionsForRuntime(false, resourceType, refreshData); }; /** * Load actions for record for runtime menu * @param resourceType * @param refreshData */ screenConfigurationModel.loadActionsForRuntimeV2 = function (resourceType, refreshData) { return executeLoadActionsForRuntime(true, resourceType, refreshData); }; /** * Gets runtime actions for new and old screen types * @param {Boolean} useV2Call - should be true for v2 screens, otherwise false. Controls corresponding method on service * @param {String} resourceType - ticket type to load actions for * @param {Boolean} refreshData - should be true, when cached value should be ignored and should be retrieved from server * @returns {Promise} */ function executeLoadActionsForRuntime(useV2Call, resourceType, refreshData) { var getActionsMethod = useV2Call ? 'loadActionsNew' : 'loadActions', cachedActions = screenConfigurationModel.runtimeActionsCache[resourceType]; if (!refreshData && cachedActions) { return $q.when(cachedActions); } var actionsPromise = screenConfigurationService[getActionsMethod]({ resourceType: resourceType }) .then(function (items) { screenConfigurationModel.runtimeActionsCache[resourceType] = items; }); screenConfigurationModel.runtimeActionsCache[resourceType] = actionsPromise; return screenConfigurationModel.runtimeActionsCache[resourceType]; } /** * Clears actions list from local cache by type * * @param {String} type - ticket type to clear cache for */ screenConfigurationModel.clearActionsListCacheForType = function (type) { if (screenConfigurationModel.runtimeActionsCache[type]) { delete screenConfigurationModel.runtimeActionsCache[type]; } }; /** * Execute provider action * @param actionId * @param resourceId */ screenConfigurationModel.executeProviderAction = function (actionId, resourceId) { return screenConfigurationService.executeProviderAction(actionId, resourceId); }; screenConfigurationModel.executeProviderActionV3 = function (actionId, resourceId, params) { return screenConfigurationService.executeProviderActionV3(actionId, resourceId, params); }; screenConfigurationModel.getSmartReporterUrl = function () { return screenConfigurationService.getSmartReporterUrl(); }; /** * Get List Of Action Templates Metadata based on resourceType * @param withMetadata * @param resourceType */ screenConfigurationModel.getTemplateList = function (withMetadata, resourceType) { return screenConfigurationService.getTemplateList({ withMetadata: withMetadata, resourceType: resourceType }); }; /** * Get List Of Action Templates Metadata based on templateId * @param templateId */ screenConfigurationModel.getTemplateById = function (templateId) { return screenConfigurationService.getTemplateById({ templateId: templateId }); }; /** * Get Existing Action Container * @param resourceType * @param supportedPlatforms */ screenConfigurationModel.getExistingContainer = function (resourceType, supportedPlatforms) { return screenConfigurationService.getExistingContainer({ resourceType: resourceType, supportedPlatforms: supportedPlatforms }); }; /** * Create custom action Url * @param actionOrder */ screenConfigurationModel.createUrlAction = function (actionList, actionOrder, resourceType) { var actionObj = { actionOrder: actionOrder, actionList: actionList, resourceType: resourceType }; return screenConfigurationService.createUrlAction(actionObj).then(handleActionsLoadSuccess); }; screenConfigurationModel.refreshServerCache = function () { return screenConfigurationService.refreshServerCache(); }; function getOotbPrimaryKeyForWidget(field, metadata) { var ootbMappingKey, widgetMember = field.members[0]; if (widgetMember) { ootbMappingKey = _.last(metadata.ootbMapping[widgetMember.name]); return _.first(ootbMappingKey.split('.')); } return ''; } function getOotbFieldValue(ticket, metadata, field) { if (field.members.length > 0) { var ticketFieldValue = {}; field.members.forEach(function (member) { var ootbMappingKey = metadata.ootbMapping[member.name]; ticketFieldValue[member.name] = (ootbMappingKey && ootbMappingKey.length > 0) ? getFieldValue(field.name, ootbMappingKey, ticket) : ticket[member.name]; }); return ticketFieldValue; } } function getFieldValue(name, ootbMappingKey, ticket) { var ticketCopy = _.cloneDeep(ticket); if (name.indexOf('CategoryTier') !== -1 || name === 'resProductName' || (_.startsWith(_.last(ootbMappingKey), 'categorizations'))) { if (!ticketCopy.categorizations.tiers) { ticketCopy.categorizations.tiers = {}; ticketCopy.categorizations.forEach(function (categorization) { _.extend(ticketCopy.categorizations.tiers, categorization.tiers); }); } if (ticketCopy.resCategorizations && !ticketCopy.resCategorizations.tiers) { ticketCopy.resCategorizations.tiers = {}; ticketCopy.resCategorizations.forEach(function (resCategorization) { _.extend(ticketCopy.resCategorizations.tiers, resCategorization.tiers); }); } } return _.get(ticketCopy, _.last(ootbMappingKey)); } /** * Private functions */ function collectTiersValues(listOfTiers) { var tiers = {}; _.forEach(listOfTiers, function (tier) { tiers[tier.name] = tier.selectedValue; }); return tiers; } /** * Get category values in the format expected by server */ function getCategoryValue(category) { if (category.dirty) { var cat = { name: category.name, tiers: collectTiersValues(category.listOfTiers) }; if (category.primary) { cat.primary = true; } if (category.company) { cat.company = category.company; } return cat; } return null; } /** * Get screen configuration by specified name * @param {String} screenName * @returns {ScreenConfigurationVO} */ function getScreenByName(screenName) { return angular.copy(screenConfigurationModel.screensCacheByName[screenName]); } /** * Returns true if value is valid * @param value * @returns {boolean} */ function isValid(value) { return angular.isDefined(value) && value !== null; } screenConfigurationModel.getScreenNameByTicketType = function (ticketType) { return _.get(screenTypeMap, ticketType); }; /** * Get screen configuration for specified ticket type * @param {String} ticketType * @return {ScreenConfigurationVO} screen configuration */ function getScreenForTicketType(ticketType) { var screenName = screenConfigurationModel.getScreenNameByTicketType(ticketType); return getScreenByName(screenName); } /** * Handler for success load of app config * @param {ApplicationConfigurationVO} appConfig */ function handleConfigurationLoadSuccess(appConfig) { screenConfigurationModel.appConfig = appConfig; var screenList = appConfig.screens; _.forEach(appConfig.screens, function (screen) { if (screen.datasource !== 'Person' && !configurationModel.isServerApplicationEnabled(screen.datasource.toLowerCase())) { screenList = _.reject(screenList, { datasource: screen.datasource }); } screenConfigurationModel.screensCacheByName[screen.name] = screen; }); screenConfigurationModel.screenList = angular.copy(screenList); if (!appConfig.screens.length) { console.log('Warning: screen list of application configuration is empty.'); screenConfigurationPromise.reject(); } } /** * Handler for success load of available field list * @param {Array} fieldList */ function handleAvailableFieldListLoadSuccess(fieldList) { var uniqueFieldsList = fieldList.reduce(function (res, field) { var isFieldAlreadySelected = res.some(function (selectedField) { return selectedField.name === field.name && selectedField.dataType === field.dataType; }); if (!isFieldAlreadySelected) { res.push(field); } return res; }, []); screenConfigurationModel.fieldList = _.sortBy(uniqueFieldsList, 'name'); screenConfigurationModel.fieldDictionary = _.indexBy(uniqueFieldsList, 'name'); } /** * Handler for success load of available field list * @param {Array} fieldList */ function handleActionsLoadSuccess(data) { _.forEach(data.actionList, function (actionItem) { actionItem.label = actionItem.labels[i18nService.language] || actionItem.labels.default; }); if (data.actionOrder === 'alphabetical') { screenConfigurationModel.actionList = _.sortBy(data.actionList, 'label'); } else { screenConfigurationModel.actionList = _.sortBy(data.actionList, 'sequenceNo'); } screenConfigurationModel.actionOrder = data.actionOrder; } /** * Handler for success load of available field list * @param {Array} fieldList */ function handleActionUrlParamsLoadSuccess(data) { screenConfigurationModel.actionUrlParams = data; } /** * Handler for success load of selected field list * @param {Array} fieldList */ function handleSelectedFieldListLoadSuccess(fieldList) { screenConfigurationModel.selectedFieldDictionary = _.indexBy(fieldList, 'name'); } /** * Handler for success load of field list * @param {Array} fieldLabels * @param {String} dataSource */ function handleFieldLabelsLoadSuccess(fieldLabels, dataSource) { if (!fieldLabelDictionary[dataSource]) { fieldLabelDictionary[dataSource] = fieldLabels; } screenConfigurationModel.fieldLabels = fieldLabels.items; } screenConfigurationModel.checkExpressionValid = function (node, fieldAcceleratorsList) { var _errorMsg = '', _checkExpressionValid = function (node) { var result; if (!_errorMsg && node) { if (node.left) { return _checkExpressionValid(node.left); } if (node.right) { return _checkExpressionValid(node.right); } if (node.type === 'Identifier') { if (!_.startsWith(node.name, '$') || !_.find(fieldAcceleratorsList, { name: node.name })) { _errorMsg = i18nService.getLocalizedStringwithParams('expression.builder.error.invalidIdentifier', node.name); return _errorMsg; } } else if (node.type === 'Compound') { _errorMsg = i18nService.getLocalizedString('expression.builder.standard.error'); return _errorMsg; } else if (node.type === 'CallExpression') { if (!_.contains(['NOOP', 'REPLACE', 'DATEADD', 'DATEDIFF', 'HASROLE', 'INGROUP', 'SELECTIONINDEX', 'SELECTIONLABEL', 'ISREQUIRED', 'ISREADONLY', 'ISHIDDEN', 'ONCHANGE'], node.callee.name)) { _errorMsg = i18nService.getLocalizedStringwithParams('expression.builder.error.functionNotSupported', node.callee.name); return _errorMsg; } _.each(node.arguments, function (item) { return _checkExpressionValid(item); }); } else if (node.type === 'ConditionalExpression') { result = _checkExpressionValid(node.test); if (!result) { result = _checkExpressionValid(node.consequent); if (!result) { return _checkExpressionValid(node.alternate); } } } } else { return _errorMsg; } }; return _checkExpressionValid(node); }; /** * Checks whether the screen supports expressions in actions * * @param {string} ticketType - type of the ticket * @returns {boolean} */ screenConfigurationModel.isTicketEnabledForProviderActionExpression = function (ticketType) { return ScreenConfigurationVO.prototype.isTicketEnabledForProviderActionExpression(ticketType); }; return screenConfigurationModel; }]); })();