"use strict"; // jscs:disable validateIndentation (function () { 'use strict'; $.widget('ui.numericSpinner', $.ui.spinner, { _format: function (value) { return value.toFixed(this._precision()); } }); angular.module('myitsmApp') .factory('customFieldLinkFunction', ['events', function (events) { return function (scope) { scope.showMeridian = window.showMeridian; scope.onFieldValueChange = function (field) { field = field || scope.data; // this is result of user interaction, so field wil always have value field.hasValue = true; scope.$parent.$emit(events.FIELD_VALUE_CHANGE, field); }; }; }]) .filter('customFieldLabelI18n', ['screenConfigurationModel', function (screenConfigurationModel) { return function (data, ticketType) { var classId; if (data.extension && data.extension.length > 0 && data.extension[0].classId) { classId = data.extension[0].classId; } var localizedField = screenConfigurationModel.getLocalizedFieldByNameForTicketType(data.name, ticketType, classId); return (localizedField && localizedField.label) ? localizedField.label : data.label; }; }]) .directive('customFieldLabel', function () { return { restrict: 'E', replace: true, template: '', link: function (scope) { //scope leaks so careful of setting anything here scope.typeOfTicket = scope.context ? (scope.context.type || scope.context.ticketType) : ''; scope.hideLabel = function () { var isDataPresent; if (scope.alwaysShowLabel) { return false; } isDataPresent = scope.data.ootb || !!scope.data.value || scope.data.value === 0; return scope.isHideLabel && (!scope.$parent.$parent.editMode || !(scope.$parent.$parent.$parent && scope.$parent.$parent.$parent.editMode)) ? scope.isHideLabel : !((!scope.data.hideLabel && isDataPresent) || scope.$parent.$parent.editMode || (scope.$parent.$parent.$parent && scope.$parent.$parent.$parent.editMode)); }; } }; }) .directive('characterCustomField', ['customFieldLinkFunction', '$filter', 'events', function (customFieldLinkFunction, $filter, events) { return { restrict: 'E', replace: true, scope: { data: '=', isEditable: '=', charLimit: '=', isHideLabel: '=', typeOfTicket: '=?' }, templateUrl: 'views/field-customization/custom-fields/character-custom-field.html', link: function (scope, element) { customFieldLinkFunction(scope); scope.status = { isCollapsed: true }; //The logic of generating Id for other ticket types is different than that of Task. Task uses Field Id 1 as its //primary Ticket Id. The input char length is returned as 1, but the task ID is more than 1 char so, UC shows the //maximum characters reached message always.The below fix is to set the field maxLength to 15. if (scope.data.label === 'Task ID') { scope.data.maxLength = 15; } scope.$watch('data.setValueFlag', function (value) { if (value && value !== '#$#') { scope.onFieldValueChange(); scope.data.setValueFlag = '#$#'; } }); if (scope.isHideLabel) { scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data); } if (scope.data.maxLength > 0) { element.find('.form-control').attr('maxlength', scope.data.maxLength); } var originaldata = _.cloneDeep(scope.data.value); scope.$on(events.SAVE_CHANGES, function () { originaldata = _.cloneDeep(scope.data.value); }); scope.$on(events.DISCARD_CHANGES, function () { scope.data.value = _.cloneDeep(originaldata); }); } }; }]) .directive('textareaCustomField', ['customFieldLinkFunction', '$filter', 'events', function (customFieldLinkFunction, $filter, events) { return { restrict: 'E', replace: true, scope: { data: '=', isEditable: '=', isHideLabel: '=', charLimit: '=?', }, templateUrl: 'views/field-customization/custom-fields/textarea-custom-field.html', link: function (scope, element) { customFieldLinkFunction(scope); scope.status = { isCollapsed: true }; scope.$watch('data.setValueFlag', function (value) { if (value && value !== '#$#') { scope.onFieldValueChange(); scope.data.setValueFlag = '#$#'; } }); if (scope.isHideLabel) { scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data); } if (scope.data.maxLength > 0) { element.find('.form-control').attr('maxlength', scope.data.maxLength); } var originaldata = _.cloneDeep(scope.data.value); scope.$on(events.SAVE_CHANGES, function () { originaldata = _.cloneDeep(scope.data.value); }); scope.$on(events.DISCARD_CHANGES, function () { scope.data.value = _.cloneDeep(originaldata); }); } }; }]) .directive('staticSelectionCustomField', ['customFieldLinkFunction', 'screenConfigurationModel', 'events', '$filter', '$rootScope', function (customFieldLinkFunction, screenConfigurationModel, events, $filter, $rootScope) { return { restrict: 'E', replace: true, scope: { data: '=', context: '=', isEditable: '=', isHideLabel: '=' }, templateUrl: 'views/field-customization/custom-fields/static-selection-custom-field.html', link: function (scope) { customFieldLinkFunction(scope); var field = scope.data; var fieldLabels = screenConfigurationModel.fieldLabels || []; var dropdownLabels; scope.dropdownOptions = { selectedOption: null }; if (EntityVO.ENTITIES_WITH_NEW_CUSTOMIZATION.indexOf(scope.context.type) !== -1) { dropdownLabels = { options: field.options }; } else { dropdownLabels = _.find(fieldLabels, function (fieldItem) { var validField = fieldItem.name === scope.data.name; if (validField && scope.context && scope.context.ticketType === EntityVO.TYPE_ASSET) { if (fieldItem.classIds && fieldItem.classIds.length) { validField = fieldItem.classIds[0] === 'ITSM AssetBase' || fieldItem.classIds[0] === scope.context.classId; } } return validField; }); } var dynamicSelectionOptions = [ { index: 0, value: 0, label: $filter('i18n')('customField.selection.label.yes') }, { index: 1, value: 1, label: $filter('i18n')('customField.selection.label.no') } ]; scope.handleRadioEnterKey = function (option) { if (!scope.data.isReadOnly && scope.isEditable) { scope.selectItem(option); if (!scope.data.radioFieldVal) { scope.data.radioFieldVal = !scope.data.radioFieldVal; } ; } }; scope.options = (field.isSelectionField()) ? dynamicSelectionOptions : (dropdownLabels && dropdownLabels.options || []); scope.selectItem = function (option) { scope.dropdownOptions.selectedOption = option; if (!_.isEmpty(option)) { if (field.isRadioField() && option.index === field.getValue()) { scope.dropdownOptions.selectedOption = null; scope.data.radioFieldVal = null; field.clearValue(); } else { field.setValue(option.name ? option.name : option.value); } } else { field.clearValue(); } scope.onFieldValueChange(); }; scope.$watch('data.setValueFlag', function (value) { if (value !== '#$#') { refreshValue(); scope.onFieldValueChange(); field.setValueFlag = '#$#'; } }); var unbindRootScopeListener = $rootScope.$on(events.TICKET_TEMPLATE_UPDATED, function (events, data) { if (scope.data.name === 'serviceType' && data) { if (data.selectedServiceType && data.selectedServiceType.name) { var option = _.find(scope.options, { name: data.selectedServiceType.name }); if (option) { scope.selectItem(option); } } else { scope.selectItem(null); } } }); if (scope.isHideLabel) { scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data); } scope.$on(events.RISK_LEVEL_CHANGE, function (events, field) { if (scope.data.name === "changeReason") { if (angular.isUndefined(scope.data.originalRequired) || scope.data.originalRequired === null) { scope.data.originalRequired = scope.data.isRequired; } scope.data.isRequired = scope.data.originalRequired || field.isRequired; } }); function refreshValue() { var selectedValueIndex = scope.data.getValue(); if (selectedValueIndex && (typeof selectedValueIndex === 'object')) { selectedValueIndex = selectedValueIndex.name; } scope.data.radioFieldVal = scope.data.value; if (angular.isDefined(selectedValueIndex) && selectedValueIndex !== null) { if (scope.data.ootb) { scope.dropdownOptions.selectedOption = _.find(scope.options, { name: selectedValueIndex }); if (!scope.dropdownOptions.selectedOption) { // Fix for SW00538722 scope.dropdownOptions.selectedOption = _.find(scope.options, { index: selectedValueIndex }); } } else { scope.dropdownOptions.selectedOption = _.find(scope.options, function (option) { return option.index === selectedValueIndex || option.name === selectedValueIndex; }); } } else { scope.dropdownOptions.selectedOption = null; } } refreshValue(); scope.$on(events.REFRESH_FIELD_VALUES, refreshValue); scope.$on('$destroy', function () { unbindRootScopeListener(); }); } }; }]) .directive('checkboxCustomField', ['customFieldLinkFunction', 'screenConfigurationModel', '$filter', 'events', function (customFieldLinkFunction, screenConfigurationModel, $filter, events) { return { restrict: 'E', replace: true, scope: { data: '=', isEditable: '=', isHideLabel: '=', typeOfTicket: '=?' }, templateUrl: 'views/field-customization/custom-fields/checkbox-custom-field.html', link: function (scope) { customFieldLinkFunction(scope); //value of checkbox ngModel should be true or false for required validation to work. scope.checkbox = { value: scope.data.value !== -1 && scope.data.value !== undefined && scope.data.value !== null }; var field = scope.data, oldFieldData = angular.copy(scope.data); var fieldLabels = screenConfigurationModel.fieldLabels || []; var checkboxLabels = _.find(fieldLabels, { name: field.name }) || field; var cbDynamicOption = getCbDynamicOption(field.value); scope.editLabel = (checkboxLabels && checkboxLabels.options && checkboxLabels.options.length) ? checkboxLabels.options[0].label : ''; if (field.isSelectionField()) { scope.cbOption = cbDynamicOption; if (field.dynamicField) { scope.alwaysShowLabel = true; } } else { scope.cbOption = (checkboxLabels && checkboxLabels.options) ? checkboxLabels.options[0] : { index: -1, label: '-' }; if (checkboxLabels && checkboxLabels.options && field.value !== checkboxLabels.options[0].index) { field.setValue(-1); scope.cbOption = { index: -1, label: '-' }; } } scope.$watch('data.setValueFlag', function (value) { if (value !== '#$#') { if (!field.isSelectionField()) { if (value !== -1) { field.setValue(-1); } else { field.setValue((checkboxLabels && checkboxLabels.options && checkboxLabels.options.length) ? checkboxLabels.options[0].index : 0); } } else { scope.cbOption = getCbDynamicOption(value); if (value) { field.clearValue(); } } scope.selectItem(); field.setValueFlag = '#$#'; } }); if (scope.isHideLabel) { scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data); } scope.selectItem = function () { if (!field.isSelectionField()) { if (!(field.value === -1 || field.value === null || field.value === undefined)) { field.setValue(-1); scope.cbOption = { index: -1, label: '-' }; } else { scope.cbOption = (checkboxLabels && checkboxLabels.options && checkboxLabels.options.length) ? checkboxLabels.options[0] : { index: 0, label: '' }; field.setValue((checkboxLabels && checkboxLabels.options && checkboxLabels.options.length) ? checkboxLabels.options[0].index : 0); } } else { if (field.value !== null && field.value !== '' && field.value !== undefined) { field.clearValue(); } else { field.setValue(scope.cbOption.index); } scope.cbOption = getCbDynamicOption(field.value); } scope.onFieldValueChange(); }; function getCbDynamicOption(value) { return (value === null) ? { index: 0, label: $filter('i18n')('customField.checkbox.label.off') } : { index: 0, label: $filter('i18n')('customField.checkbox.label.on') }; } function handleDiscardChanges() { var oldVal = oldFieldData.getValue(); if (field.isSelectionField()) { if (oldVal === null || oldVal === '' || oldVal === undefined) { field.clearValue(); } else { field.setValue(scope.cbOption.index); } scope.cbOption = getCbDynamicOption(field.value); } else { if (oldVal === -1 || oldVal === null || oldVal === undefined) { field.setValue(-1); scope.cbOption = { index: -1, label: '-' }; } else { scope.cbOption = (checkboxLabels && checkboxLabels.options && checkboxLabels.options.length) ? checkboxLabels.options[0] : { index: 0, label: '' }; field.setValue(oldVal); } } } function updateOldDataField() { oldFieldData = angular.copy(scope.data); } scope.$on(events.RESET_DYNAMIC_FIELDS, handleDiscardChanges); scope.$on(events.UPDATE_DYNAMIC_DATA, updateOldDataField); } }; }]) .directive('numberCustomField', ['customFieldLinkFunction', '$filter', 'events', function (customFieldLinkFunction, $filter, events) { return { restrict: 'E', replace: true, scope: { data: '=', isEditable: '=', isHideLabel: '=', typeOfTicket: '=?' }, templateUrl: 'views/field-customization/custom-fields/number-custom-field.html', link: function (scope) { scope.data.step = Math.pow(10, -scope.data.precision); scope.$watch('data.setValueFlag', function (value) { if (value !== '#$#') { scope.onFieldValueChange(); scope.data.setValueFlag = '#$#'; } }); customFieldLinkFunction(scope); if (scope.isHideLabel) { scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data); } var originaldata = _.cloneDeep(scope.data.value); scope.$on(events.SAVE_CHANGES, function () { originaldata = _.cloneDeep(scope.data.value); }); scope.$on(events.DISCARD_CHANGES, function () { scope.data.value = _.cloneDeep(originaldata); }); } }; }]) .directive('dateTimeCustomField', ['customFieldLinkFunction', '$filter', 'events', 'configurationModel', function (customFieldLinkFunction, $filter, events, configurationModel) { return { restrict: 'E', replace: true, scope: { data: '=', isEditable: '=', isHideLabel: '=', typeOfTicket: '=?' }, templateUrl: 'views/field-customization/custom-fields/datetime-custom-field.html', link: function (scope) { customFieldLinkFunction(scope); scope.status = { opened: false }; 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.$watch('data.setValueFlag', function (value) { if (value && value !== '#$#') { scope.onFieldValueChange(); scope.data.setValueFlag = '#$#'; } }); if (scope.isHideLabel) { scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data); } scope.open = function ($event) { $event.preventDefault(); $event.stopPropagation(); scope.status.opened = true; }; var originaldata = _.cloneDeep(scope.data.value); scope.$on(events.SAVE_CHANGES, function () { originaldata = _.cloneDeep(scope.data.value); }); scope.$on(events.DISCARD_CHANGES, function () { scope.data.value = _.cloneDeep(originaldata); }); } }; }]) .directive('dateCustomField', ['customFieldLinkFunction', '$filter', 'configurationModel', function (customFieldLinkFunction, $filter, configurationModel) { return { restrict: 'E', replace: true, scope: { data: '=', isEditable: '=', isHideLabel: '=' }, templateUrl: 'views/field-customization/custom-fields/date-custom-field.html', link: function (scope) { customFieldLinkFunction(scope); scope.status = { opened: false }; scope.datePickerOptions = { startingDay: configurationModel.getWeekStartingDay(), 'show-weeks': false, minDate: moment().year(1970).month(0).date(2) }; if (!scope.data.isDateTimeField()) { if (scope.data.value) { /* We are using the date filter in date-custom-field template and the date filter converts the epoch value according to the current timezone. We need to display date values in GMT. The getTimezoneOffset () method returns the time difference between UTC time and local time in minutes. Adding timezone offset as it is being removed by the date filter */ var gmtDate = new Date(scope.data.value); var fieldValue = gmtDate.valueOf() + (gmtDate.getTimezoneOffset() * 60000); if (fieldValue) { scope.data.value = fieldValue; } } } scope.$watch('data.setValueFlag', function (value) { if (value && value !== '#$#') { scope.onFieldValueChange(); scope.data.setValueFlag = '#$#'; } }); if (scope.isHideLabel) { scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data); } scope.open = function ($event) { $event.preventDefault(); $event.stopPropagation(); scope.status.opened = true; }; } }; }]) .directive('timeCustomField', ['customFieldLinkFunction', '$filter', 'events', function (customFieldLinkFunction, $filter, events) { return { restrict: 'E', replace: true, scope: { data: '=', isEditable: '=', isHideLabel: '=' }, templateUrl: 'views/field-customization/custom-fields/time-custom-field.html', link: function (scope) { scope.$watch('data.setValueFlag', function (value) { if (value && value !== '#$#') { scope.onFieldValueChange(); scope.data.setValueFlag = '#$#'; } }); customFieldLinkFunction(scope); if (scope.isHideLabel) { scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data); } var originaldata = _.cloneDeep(scope.data.value); scope.$on(events.SAVE_CHANGES, function () { originaldata = _.cloneDeep(scope.data.value); }); scope.$on(events.DISCARD_CHANGES, function () { scope.data.value = _.cloneDeep(originaldata); }); } }; }]) .directive('validNumber', ['$timeout', function ($timeout) { return { restrict: 'A', require: 'ngModel', link: function (scope, elem, attr, ctrl) { ctrl.$parsers.push(checkPrecision, checkRequired); function checkPrecision(val) { var stringVal = val ? val.toString() : ''; // do nothing if we got an invalid number or smth like '123' or '123.' if (!stringVal || stringVal.indexOf('.') === -1 || !stringVal.split('.')[1].length) { return val; } var precision = parseInt(attr.precision); var precisionLen = stringVal.split('.')[1].length; var valid = true; var newVal = val; var sliceAmount = 0; var parseVal = ''; if (!precision) { // precision=0 but we got 123.4 valid = false; sliceAmount = precisionLen + 1; // +1 means to cut decimal separator '.' as well } else if (precision < precisionLen) { // precision=2 but we got 123.456 valid = false; sliceAmount = precisionLen - attr.precision; } if (!valid) { newVal = parseFloat(stringVal.slice(0, 0 - sliceAmount)); // slice last sliceAmount digits parseVal = stringVal.slice(0, 0 - sliceAmount); $timeout(function () { ctrl.$setViewValue(attr.numberType === 'integer' ? parseInt(parseVal) : parseFloat(parseVal)); ctrl.$render(); }, 0); } return newVal; } function checkRequired(val) { if (JSON.parse(attr.numberRequired)) { if (ctrl.$isEmpty(val)) { ctrl.$setValidity('required', false); } else if (!isNaN(val)) { ctrl.$setValidity('required', true); return val; } } else { ctrl.$setValidity('required', true); return val; } } } }; }]) .directive('numberInput', ['i18nService', function (i18nService) { return { restrict: 'A', require: 'ngModel', scope: { min: '@', max: '@', precision: '@', numberType: '@' }, link: function (scope, element, attrs, ctrl) { var min = parseFloat(attrs.min); var max = parseFloat(attrs.max); var precision = parseInt(attrs.precision); if (isNaN(precision)) { precision = 0; } var step = Math.pow(10, -precision); var numberType = attrs.numberType; element.numericSpinner({ step: step, spin: function (event, ui) { var newValue = ui.value; // min/max limits are enforced here because // ui.spinner has issues with extreme max and min values if (newValue > max) { newValue = max; } if (newValue < min) { newValue = min; } ctrl.$setViewValue(newValue); scope.$apply(); } }); ctrl.$formatters.unshift(function () { var floatValue = parseFloat(ctrl.$modelValue); if (isNaN(floatValue)) { return ctrl.$modelValue; } else { return floatValue.toFixed(precision); } }); // this fix triggers validation on clearing of required input var keyUpHandler = function (numberInput, digits) { if (digits.length === 1 && digits[0] === '') { ctrl.$setViewValue(''); scope.$apply(); } }; var radixPoint = i18nService.language === 'de' ? ',' : '.'; switch (numberType) { case 'integer': element.inputmask('integer', { rightAlign: false, onKeyUp: keyUpHandler }); break; case 'decimal': element.inputmask('decimal', { rightAlign: false, skipRadixDance: true, radixPoint: radixPoint, digits: precision, onKeyUp: keyUpHandler }); break; case 'real': element.inputmask('real', { rightAlign: false, skipRadixDance: true, radixPoint: radixPoint, digits: precision, onKeyUp: keyUpHandler }); break; } } }; }]) .directive('menuCustomField', ['customFieldLinkFunction', 'screenConfigurationModel', 'screenConfigurationService', 'metadataModel', 'objectValueMapperService', '$filter', 'events', '$timeout', function (customFieldLinkFunction, screenConfigurationModel, screenConfigurationService, metadataModel, objectValueMapperService, $filter, events, $timeout) { return { restrict: 'E', replace: true, scope: { data: '=', context: '=', isEditable: '=', isNew: '=?', getFieldValue: '&', onSelectCb: '&', isHideLabel: '=' }, templateUrl: 'views/field-customization/custom-fields/menu-custom-field.html', link: function (scope) { customFieldLinkFunction(scope); var field = scope.data, context = scope.context, contextType = context && context.ticketType === EntityVO.TYPE_ASSET ? context.ticketType : context.type, classId = context && context.ticketType === EntityVO.TYPE_ASSET ? context.classId : null; scope.getCustomFieldFieldValue = scope.getFieldValue(); scope.onSelectCb = scope.onSelectCb() ? scope.onSelectCb() : angular.noop; scope.state = { loading: false }; var tooltipPromise; if (field.name == 'company') { field.isLocationCompany = true; } scope.$watch('data.setValueFlag', function (value) { if (value !== '#$#') { if (!_.isEmpty(value)) { scope.data.setValue(value); scope.data.setLinkedFieldValue(value); //Todo: fetch corresponding field option from backend by passing the menu name and value and set them correctly /*scope.state.loading = true; return scope.loadDynamicSelectionValues(value) .then(function (resp) { var selectedOption = _.find(resp, function (option) { return option.name === value || option.label === value; }); if (selectedOption) { scope.selectItem(selectedOption); } }).finally(function () { scope.state.loading = false; scope.data.setValueFlag = '#$#'; })*/ } else { scope.state.loading = false; scope.data.clearValue(); scope.data.clearLinkedFieldValue(); } scope.onFieldValueChange(); scope.data.setValueFlag = '#$#'; } }); if (scope.isHideLabel) { scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data); } metadataModel.getMetadataByType(EntityVO.TYPE_GLOBAL).then(function (metadata) { if (metadata.configurationParameters.CustomizationTypeaheadLength) { scope.typeaheadMinLength = parseInt(metadata.configurationParameters.CustomizationTypeaheadLength); } else { scope.typeaheadMinLength = 3; } }); scope.loadDynamicSelectionValues = function (searchText) { return metadataModel.getMetadataByType(contextType).then(function (metadata) { var dependencies = {}; if (contextType === EntityVO.TYPE_TASK || contextType === EntityVO.TYPE_WORKORDER) { var locationCompany = context.locationCompany; } //For new customization types we need to get dependency values from objectValueMapperService as data in context is stale if (_.includes(EntityVO.ENTITIES_WITH_NEW_CUSTOMIZATION, contextType)) { _.forEach(field.dependency, function (dependentField) { var fieldObj = objectValueMapperService.getFieldByName(dependentField.name); dependencies[dependentField.name] = objectValueMapperService.getExactValueByFieldName(dependentField.name) || null; //since there is no locationcompnay field for Incident create, we need to use the customer company value if (!fieldObj && dependentField.name === 'locationCompany') { fieldObj = objectValueMapperService.getFieldByName('company'); dependencies[dependentField.name] = objectValueMapperService.getExactValueByFieldName('company'); if (dependencies[dependentField.name] === '') { dependencies[dependentField.name] = locationCompany; } } if (fieldObj && fieldObj.dataType === 'dropdown') { if (fieldObj.options && fieldObj.options.length > 0) { _.forEach(fieldObj.options, function (option) { if (option.name === dependencies[dependentField.name]) { dependencies[dependentField.name] = option.index; } }); } } else if (fieldObj && fieldObj.dataType === 'widget' && fieldObj.members.length && fieldObj.members[0].dataType === 'dropdown') { if (fieldObj.members[0].options && fieldObj.members[0].options.length > 0) { _.forEach(fieldObj.members[0].options, function (option) { if (option.name === dependencies[dependentField.name]) { dependencies[dependentField.name] = option.index; } }); } } }); } else { _.forEach(field.dependency, function (dependentField) { dependencies[dependentField.name] = scope.getCustomFieldFieldValue(dependentField.name); //get value for custom field (lookup in fieldsConfig and in context.customFields.fieldName) if (_.isUndefined(dependencies[dependentField.name]) && contextType !== 'asset') { //Warning:: Special handling for fields done here, but should have been handled by backend //As agreed backend will either send the field and metadata mapping or accept the name in the field object for dependencies on dropdown fields //e.g. In the menu/expand/ call we will send {priority: "High"} instead of {priority: 2} //Due to time constraints this was hardcoded in UC instead of backend handling var specialFieldsList = [EntityVO.TYPE_PRIORITY, EntityVO.TYPE_URGENCY, EntityVO.TYPE_IMPACT, EntityVO.TYPE_STATUS]; dependencies[dependentField.name] = screenConfigurationService.getContextPropertyByMetadataMapping(context, metadata, dependentField.name, scope.isNew) || null; if (dependencies[dependentField.name] !== null && dependencies[dependentField.name] !== undefined && (contextType === EntityVO.TYPE_KNOWNERROR || contextType === EntityVO.TYPE_PROBLEM) && _.includes(specialFieldsList, dependentField.name)) { var optionsList; switch (dependentField.name) { case EntityVO.TYPE_PRIORITY: optionsList = metadata.priorities; break; case EntityVO.TYPE_URGENCY: optionsList = metadata.urgencies; break; case EntityVO.TYPE_IMPACT: optionsList = metadata.impacts; break; case EntityVO.TYPE_STATUS: optionsList = metadata.statuses; break; default: optionsList = []; break; } if (optionsList.length) { dependencies[dependentField.name] = _.result(_.find(optionsList, { 'name': dependencies[dependentField.name] }), 'index'); } } } else if (_.isUndefined(dependencies[dependentField.name]) && contextType === 'asset') { //DRSMX-66920 : Menu dependency in SmartIT not working as expected //When dependent field names are different than the field names coming in the asset metaData, backend is expecting to pass the dependent fieldNames as per metaData var metaDataKey = metadata && metadata.ootbMapping && metadata.ootbMapping[dependentField.name] && metadata.ootbMapping[dependentField.name][0]; if (metaDataKey && metaDataKey !== dependentField.name) { var dependentFieldValue = screenConfigurationService.getContextPropertyByMetadataMapping(context, metadata, dependentField.name); if (!dependentFieldValue && metaDataKey === 'companyName') { dependentFieldValue = context && context.company && context.company.name ? context.company.name : ''; } else if (!dependentFieldValue && metaDataKey === 'siteGroup') { dependentFieldValue = context && context.site && context.site.siteGroup ? context.site.siteGroup : ''; } else if (!dependentFieldValue && metaDataKey === 'siteName') { dependentFieldValue = context && context.site && context.site.name ? context.site.name : ''; } else if (!dependentFieldValue && metaDataKey === 'siteRegion') { dependentFieldValue = context && context.site && context.site.region ? context.site.region : ''; } delete dependencies[dependentField.name]; dependencies[metaDataKey] = dependentFieldValue ? dependentFieldValue : null; } else { dependencies[dependentField.name] = screenConfigurationService.getContextPropertyByMetadataMapping(context, metadata, dependentField.name); } } }); } var hasCreateScreen = scope.isNew && _.includes([EntityVO.TYPE_PROBLEM, EntityVO.TYPE_KNOWNERROR], contextType) ? false : scope.isNew; return screenConfigurationModel.loadDynamicSelectionFieldLabels(contextType, field.menu, searchText, dependencies, classId, field.name, hasCreateScreen).then(function (data) { if (tooltipPromise) { $timeout.cancel(scope.tooltipPromise); } scope.exceedsChunkSize = data.exceedsChunkSize; scope.state.isTooltipOpen = data.exceedsChunkSize; tooltipPromise = $timeout(function () { scope.state.isTooltipOpen = false; }, 10000); return data.items; }); }).finally(function () { scope.state.loading = false; }); }; scope.onInputFocusBlur = function () { scope.state.isTooltipOpen = false; }; scope.selectItem = function (option) { var newFieldValue; if (!_.isEmpty(option)) { if (field.name === 'assignee' || field.name === 'assigneeName' || field.name === 'managerName') { newFieldValue = option.label; field.assigneeLoginId = option.value; } else { //handle 'case 3', option -> {label: 'aaa', value: 'bbb'} && _.isUndefined(field.valueField) == true -> set value instead of label to field newFieldValue = (!field.valueField && option.value) ? option.value : option.label; } field.setValue(newFieldValue); field.setLinkedFieldValue(option.value); if (_.includes(EntityVO.ENTITIES_WITH_NEW_CUSTOMIZATION, contextType) && field.valueField) { objectValueMapperService.setByProperty(field.valueField, 'value', option.value); } scope.$emit(events.CLEAR_DEPENDANT_FIELDS, field.name); } else { field.clearValue(); field.clearLinkedFieldValue(); if (_.includes(EntityVO.ENTITIES_WITH_NEW_CUSTOMIZATION, contextType) && field.valueField) { objectValueMapperService.setByProperty(field.valueField, 'value', ''); } } scope.onFieldValueChange(); scope.onSelectCb(); scope.$emit(events.CUSTOM_FIELD_VALUE_CHANGE); }; } }; }]) .directive('groupCustomField', ['customFieldLinkFunction', 'events', 'screenConfigurationService', 'metadataModel', '$filter', 'objectValueMapperService', function (customFieldLinkFunction, events, screenConfigurationService, metadataModel, $filter, objectValueMapperService) { return { restrict: 'E', replace: true, scope: { data: '=', context: '=', getFieldValue: '&', isNew: '=?', isHideLabel: '=' }, templateUrl: 'views/field-customization/custom-fields/group-custom-field.html', controller: 'LaunchActionController', link: function (scope) { var context = scope.context, contextType = context && context.ticketType === EntityVO.TYPE_ASSET ? context.ticketType : context.type; customFieldLinkFunction(scope); scope.$watch('$parent.editMode', function (newValue) { scope.editMode = newValue; }, true); scope.$watch('context', function () { scope.checkEditable(); }, true); scope.getFieldValue = scope.getFieldValue(); scope.isEditable = function (field) { if (scope.context.type === EntityVO.TYPE_ASSET) { return !field.isReadOnly; } else { return field.isEditable(scope.context.accessMappings); } }; if (scope.isHideLabel) { scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data); } scope.clearDependantFieldValues = function (event, fieldName) { _.forEach(scope.data.members, function (groupField) { if (!groupField.dependency || !groupField.dependency.length) { groupField.groupEditable = true; return; } else if (_.findIndex(groupField.dependency, { name: fieldName }) > -1) { groupField.clearValue(); groupField.clearLinkedFieldValue(); scope.onFieldValueChange(groupField); } }); }; //todo: minimize calls of function (tier3 changed -> no need to check editability of tier1) scope.checkEditable = function () { var editGroup = true; metadataModel.getMetadataByType(contextType).then(function (metadata) { _.forEach(scope.data.members, function (groupField) { if (!groupField.dependency || !groupField.dependency.length) { groupField.groupEditable = true; return; } _.forEach(groupField.dependency, function (dependency) { if (!scope.getFieldValue(dependency.name)) { var fieldValue = objectValueMapperService.getExactValueByFieldName(dependency.name); if (!fieldValue) { editGroup = false; } } }); if (!editGroup) { groupField.groupEditable = false; groupField.clearValue(); groupField.clearLinkedFieldValue(); scope.onFieldValueChange(groupField); } else { groupField.groupEditable = true; } }); }); }; scope.checkEditable(); scope.$on(events.REFRESH_FIELD_VALUES, scope.checkEditable); scope.$on(events.CLEAR_DEPENDANT_FIELDS, scope.clearDependantFieldValues); } }; }]); }());