diff --git a/i18n/en-US.json b/i18n/en-US.json index 110c0ca..3cb176c 100644 --- a/i18n/en-US.json +++ b/i18n/en-US.json @@ -254,9 +254,15 @@ }, "__comment": "UI-1351: Add ability to configure feature keys for SIP devices in SmartPBX", "__version": "v3.20_s4", - "featureKeys": { - "menuTitle": "Feature Keys", - "description": "Feature key", + "keys": { + "featureKeys": { + "title": "Feature Keys", + "label": "Feature key" + }, + "comboKeys": { + "title": "Combo Keys", + "label": "Combo key" + }, "labels": { "user": "User", "parkingSpot": "Parking Spot", @@ -689,7 +695,11 @@ "deleteUserName": "Delete \"{{variable}}\"", "proceed": "Proceed", "deleteDevices": "Also remove this user's devices from the system", - "deleteDevicesHelp": "If you leave this option unchecked, we'll just unassign these devices and they will show up in the list of Spare Devices" + "deleteDevicesHelp": "If you leave this option unchecked, we'll just unassign these devices and they will show up in the list of Spare Devices", + "__comment": "UI-2467: also remove conferences when deleting a user from smartpbx", + "__version": "4.0", + "deleteConferences": "Also remove this user's conferences from the system", + "deleteConferencesHelp": "If you leave this option unchecked, you won't be able to use the user's conference number anywhere else, as it will still be used by that conference." } }, diff --git a/submodules/devices/devices.js b/submodules/devices/devices.js index 191bca1..cf4a274 100644 --- a/submodules/devices/devices.js +++ b/submodules/devices/devices.js @@ -155,6 +155,20 @@ define(function(require){ }); }, + getKeyTypes: function(data) { + var types = []; + + if (data.hasOwnProperty('feature_keys') && data.feature_keys.iterate > 0) { + types.push('feature_keys'); + } + + if (data.hasOwnProperty('combo_keys') && data.combo_keys.iterate > 0) { + types.push('combo_keys'); + } + + return _.isEmpty(types) ? null : types; + }, + devicesRenderEdit: function(args) { var self = this, data = args.data, @@ -166,28 +180,32 @@ define(function(require){ self.devicesGetEditData(data, function(dataDevice) { if (dataDevice.hasOwnProperty('provision')) { self.devicesGetIterator(dataDevice.provision, function(template) { - if (template.hasOwnProperty('feature_keys') && template.feature_keys.iterate > 0) { - if (!dataDevice.provision.hasOwnProperty('feature_keys')) { - dataDevice.provision.feature_keys = {}; - } + var keyTypes = self.getKeyTypes(template); + + if (keyTypes) { + self.devicesListUsers({ + success: function(users) { + _.each(keyTypes, function(type, idx) { + if (!dataDevice.provision.hasOwnProperty(type)) { + dataDevice.provision[type] = {}; + } - for (var i = 0, len = template.feature_keys.iterate; i < len; i++) { - if (!dataDevice.provision.feature_keys.hasOwnProperty(i)) { - dataDevice.provision.feature_keys[i] = { type: 'none' }; - } - } + var i = 0, + len = template[type].iterate; + for (; i < len; i++) { + if (!dataDevice.provision[type].hasOwnProperty(i)) { + dataDevice.provision[type][i] = { + type: 'none' + } + } + } + }); - self.callApi({ - resource: 'user.list', - data: { - accountId: self.accountId - }, - success: function(data, status) { - var keyTypes = [ 'none', 'presence', 'parking', 'personal_parking', 'speed_dial' ], + var actions = [ 'none', 'presence', 'parking', 'personal_parking', 'speed_dial' ], parkingSpots = [], extra; - data.data.sort(function(a, b) { + users.sort(function(a, b) { return a.last_name.toLowerCase() > b.last_name.toLowerCase() ? 1 : -1; }); @@ -195,22 +213,38 @@ define(function(require){ parkingSpots[i] = i + 1; } - keyTypes.forEach(function(val, idx, arr) { - arr[idx] = { id: val, text: self.i18n.active().devices.popupSettings.featureKeys.types[val] }; + _.each(actions, function(action, idx, list) { + list[idx] = { + id: action, + text: self.i18n.active().devices.popupSettings.keys.types[action] + }; - if (val !== 'none') { - arr[idx].info = self.i18n.active().devices.popupSettings.featureKeys.info.types[val]; + if (action !== 'none') { + list[idx].info = self.i18n.active().devices.popupSettings.keys.info.types[action]; } }); extra = { - users: data.data, - featureKeys:{ + provision: { + users: users, parkingSpots: parkingSpots, - types: keyTypes + keyActions: actions, + keys: [] } }; + _.each(keyTypes, function(key, idx) { + var camelCaseKey = self.devicesSnakeToCamel(key); + + extra.provision.keys.push({ + id: key, + type: camelCaseKey, + title: self.i18n.active().devices.popupSettings.keys[camelCaseKey].title, + label: self.i18n.active().devices.popupSettings.keys[camelCaseKey].label, + data: dataDevice.provision[key] + }); + }); + dataDevice.extra = dataDevice.hasOwnProperty('extra') ? $.extend(true, {}, dataDevice.extra, extra) : extra; self.devicesRenderDevice(dataDevice, callbackSave, callbackDelete); @@ -279,23 +313,28 @@ define(function(require){ }))), deviceForm = templateDevice.find('#form_device'); - if (data.hasOwnProperty('provision') && data.provision.hasOwnProperty('feature_keys')) { - var section = '.tabs-section[data-section="featureKeys"] '; + if (data.extra.hasOwnProperty('provision') && data.extra.provision.hasOwnProperty('keys')) { + _.each(data.extra.provision.keys, function(value, idx) { + var section = '.tabs-section[data-section="' + value.type + '"] '; - _.each(data.provision.feature_keys, function(val, key){ - var group = '.control-group[data-id="' + key + '"] ', - value = '.feature-key-value[data-type="' + val.type + '"]'; + _.each(value.data, function(val, key) { + var group = '.control-group[data-id="' + key + '"] ', + value = '.feature-key-value[data-type="' + val.type + '"]'; - templateDevice - .find(section.concat(group, value)) - .addClass('active') - .find('[name="provision.feature_keys[' + key + '].value"]') - .val(val.value); + templateDevice + .find(section.concat(group, value)) + .addClass('active') + .find('[name="provision.feature_keys[' + key + '].value"]') + .val(val.value); + }); }); - $.each(templateDevice.find('.feature-key-index'), function(idx, val) { - $(val).text(parseInt($(val).text(), 10) + 1); - }); + templateDevice + .find('.feature-key-index') + .each(function(idx, el) { + $(el) + .text(parseInt($(el).text(), 10) + 1); + }); } if ( data.extra.hasE911Numbers ) { @@ -515,7 +554,7 @@ define(function(require){ setTimeout(function() { var action = ($this.hasClass('collapsed') ? 'show' : 'hide').concat('Info'); - $this.find('.text').text(self.i18n.active().devices.popupSettings.featureKeys.info.link[action]); + $this.find('.text').text(self.i18n.active().devices.popupSettings.keys.info.link[action]); }); }); @@ -613,18 +652,29 @@ define(function(require){ }); } - /** - * form2object sends feature_keys back as an array even if the first key is 1 - * feature_key needs to be coerced into an object to match the datatype in originalData - */ - if (formData.hasOwnProperty('provision') && formData.provision.hasOwnProperty('feature_keys')) { - var featureKeys = {}; + if (formData.hasOwnProperty('provision') && formData.provision.hasOwnProperty('keys')) { + /** + * form2object sends keys back as arrays even if the first key is 1 + * they needs to be coerced into an object to match the datatype in originalData + */ + _.each(formData.provision.keys, function(value, key, list) { + var keys = {}; + + list[key].forEach(function(val, idx) { + if (val.type !== 'none') { + keys[idx] = val; + } + }); - formData.provision.feature_keys.forEach(function(val, idx) { - featureKeys[idx] = val; + if (_.isEmpty(keys)) { + delete originalData.provision[key]; + } + else { + originalData.provision[key] = keys; + } }); - formData.provision.feature_keys = featureKeys; + delete formData.provision.keys; } var mergedData = $.extend(true, {}, originalData, formData); @@ -662,19 +712,6 @@ define(function(require){ delete mergedData.media.fax.option; } - // Remove feature keys that are not defined - if (mergedData.hasOwnProperty('provision') && mergedData.provision.hasOwnProperty('feature_keys')) { - for (var key in mergedData.provision.feature_keys) { - if (mergedData.provision.feature_keys[key].type === 'none') { - delete mergedData.provision.feature_keys[key]; - } - } - - if (_.isEmpty(mergedData.provision.feature_keys)) { - delete mergedData.provision.feature_keys; - } - } - if(mergedData.hasOwnProperty('caller_id') && mergedData.caller_id.hasOwnProperty('emergency') && mergedData.caller_id.emergency.hasOwnProperty('number') && mergedData.caller_id.emergency.number === '') { delete mergedData.caller_id.emergency.number; @@ -947,6 +984,10 @@ define(function(require){ return formattedData; }, + devicesSnakeToCamel: function(string) { + return string.replace(/(\_\w)/g, function (match) { return match[1].toUpperCase(); }); + }, + /* Utils */ devicesDeleteDevice: function(deviceId, callback) { var self = this; @@ -990,35 +1031,27 @@ define(function(require){ } }, success: function(data) { - monster.pub('common.numbers.getListFeatures', function(viewFeatures) { - var e911Numbers = {}; - _.each(data.data.numbers, function(val, key) { - if(val.features.indexOf('e911') >= 0) { - e911Numbers[key] = self.devicesFormatNumber(val, viewFeatures); - } - }); + var e911Numbers = {}; - callback(e911Numbers); + _.each(data.data.numbers, function(val, key) { + if(val.features.indexOf('e911') >= 0) { + e911Numbers[key] = self.devicesFormatNumber(val); + } }); + + callback(e911Numbers); } }); }, - devicesFormatNumber: function(value, viewFeatures) { + devicesFormatNumber: function(value) { var self = this; - value.viewFeatures = $.extend(true, {}, viewFeatures); if('locality' in value) { value.isoCountry = value.locality.country || ''; value.friendlyLocality = 'city' in value.locality ? value.locality.city + ('state' in value.locality ? ', ' + value.locality.state : '') : ''; } - _.each(value.features, function(feature) { - if(feature in value.viewFeatures) { - value.viewFeatures[feature].active = 'active'; - } - }); - return value; }, @@ -1228,6 +1261,23 @@ define(function(require){ else { callbackError && callbackError(); } + }, + + devicesListUsers: function(args) { + var self = this; + + self.callApi({ + resource: 'user.list', + data: { + accountId: self.accountId + }, + success: function(data, status) { + args.hasOwnProperty('success') && args.success(data.data); + }, + error: function(data, status) { + args.hasOwnProperty('error') && args.error(); + } + }); } }; diff --git a/submodules/groups/groups.css b/submodules/groups/groups.css index f7dcabf..98a0cd9 100644 --- a/submodules/groups/groups.css +++ b/submodules/groups/groups.css @@ -370,14 +370,6 @@ white-space:pre-wrap; } -#groups_container .list-wrapper .item-row .features > i { - display: none; -} - -#groups_container .list-wrapper .item-row .features > i.active { - display: inline-block; -} - #groups_container .list-wrapper .item-row .locality { display: none; border-left: 1px solid #CCC; diff --git a/submodules/groups/groups.js b/submodules/groups/groups.js index e61bdb2..8351603 100644 --- a/submodules/groups/groups.js +++ b/submodules/groups/groups.js @@ -445,10 +445,22 @@ define(function(require){ self.groupsGetNumbersData(groupId, function(data) { self.groupsFormatNumbersData(data, function(data) { - template = $(monster.template(self, 'groups-numbers', $.extend(true, {}, data, { - isCnamEnabled: monster.util.isNumberFeatureEnabled('cnam'), - isE911Enabled: monster.util.isNumberFeatureEnabled('e911') - }))); + template = $(monster.template(self, 'groups-numbers', data)); + + _.each(data.assignedNumbers, function(numberData, numberId) { + numberData.phoneNumber = numberId; + + var numberDiv = template.find('[data-id="' + numberId + '"]'), + argsFeatures = { + target: numberDiv.find('.edit-features'), + numberData: numberData, + afterUpdate: function(features) { + monster.ui.paintNumberFeaturesIcon(features, numberDiv.find('.features')); + } + }; + + monster.pub('common.numberFeaturesMenu.render', argsFeatures); + }); self.groupsBindNumbers(template, data); @@ -1063,83 +1075,6 @@ define(function(require){ } }); - if (monster.util.isNumberFeatureEnabled('e911')) { - template.on('click', '.e911-number', function() { - var e911Cell = $(this).parents('.item-row').first(), - phoneNumber = e911Cell.data('id'); - - if(phoneNumber) { - var args = { - phoneNumber: phoneNumber, - callbacks: { - success: function(data) { - if(!($.isEmptyObject(data.data.e911))) { - e911Cell.find('.features i.feature-e911').addClass('active'); - } - else { - e911Cell.find('.features i.feature-e911').removeClass('active'); - } - } - } - }; - - monster.pub('common.e911.renderPopup', args); - } - }); - } - - if (monster.util.isNumberFeatureEnabled('cnam')) { - template.on('click', '.callerId-number', function() { - var cnamCell = $(this).parents('.item-row').first(), - phoneNumber = cnamCell.data('id'); - - if(phoneNumber) { - var args = { - phoneNumber: phoneNumber, - callbacks: { - success: function(data) { - if('cnam' in data.data && data.data.cnam.display_name) { - cnamCell.find('.features i.feature-outbound_cnam').addClass('active'); - } else { - cnamCell.find('.features i.feature-outbound_cnam').removeClass('active'); - } - - if('cnam' in data.data && data.data.cnam.inbound_lookup) { - cnamCell.find('.features i.feature-inbound_cnam').addClass('active'); - } else { - cnamCell.find('.features i.feature-inbound_cnam').removeClass('active'); - } - } - } - }; - - monster.pub('common.callerId.renderPopup', args); - } - }); - } - - template.on('click', '.prepend-number', function() { - var prependCell = $(this).parents('.item-row').first(), - phoneNumber = prependCell.data('id'); - - if(phoneNumber) { - var args = { - phoneNumber: phoneNumber, - callbacks: { - success: function(data) { - if('prepend' in data.data && data.data.prepend.enabled) { - prependCell.find('.features i.feature-prepend').addClass('active'); - } else { - prependCell.find('.features i.feature-prepend').removeClass('active'); - } - } - } - }; - - monster.pub('common.numberPrepend.renderPopup', args); - } - }); - template.on('click', '.actions .spare-link:not(.disabled)', function(e) { e.preventDefault(); @@ -1155,16 +1090,23 @@ define(function(require){ template.find('.empty-row').hide(); _.each(numberList, function(val, idx) { - val.isLocal = val.features.indexOf('local') > -1; - template .find('.list-assigned-items') .append($(monster.template(self, 'groups-numbersItemRow', { - isCnamEnabled: monster.util.isNumberFeatureEnabled('cnam'), - isE911Enabled: monster.util.isNumberFeatureEnabled('e911'), number: val }))); + var numberDiv = template.find('[data-id="'+val.phoneNumber+'"]'), + args = { + target: numberDiv.find('.edit-features'), + numberData: val, + afterUpdate: function(features) { + monster.ui.paintNumberFeaturesIcon(features, numberDiv.find('.features')); + } + }; + + monster.pub('common.numberFeaturesMenu.render', args); + extraSpareNumbers = _.without(extraSpareNumbers, val.phoneNumber); }); @@ -1186,23 +1128,26 @@ define(function(require){ searchType: $(this).data('type'), callbacks: { success: function(numbers) { - monster.pub('common.numbers.getListFeatures', function(features) { - _.each(numbers, function(number, k) { - number.viewFeatures = $.extend(true, {}, features); - number.phoneNumber = number.id; - - monster.util.populateBooleansNumberFeatures(number); - number.extra.hasFeatures = number.extra.hasE911 || number.extra.hasPrepend || number.extra.hasCnam; + _.each(numbers, function(number, k) { + number.phoneNumber = number.id; - var rowTemplate = $(monster.template(self, 'groups-numbersItemRow', { + var rowTemplate = $(monster.template(self, 'groups-numbersItemRow', { number: number - })); + })), + argsFeatures = { + target: rowTemplate.find('.edit-features'), + numberData: number, + afterUpdate: function(features) { + monster.ui.paintNumberFeaturesIcon(features, rowTemplate.find('.features')); + } + }; - monster.ui.tooltips(rowTemplate); + monster.pub('common.numberFeaturesMenu.render', argsFeatures); - template.find('.list-unassigned-items .empty-row').hide(); - template.find('.list-unassigned-items').append(rowTemplate); - }); + monster.ui.tooltips(rowTemplate); + + template.find('.list-unassigned-items .empty-row').hide(); + template.find('.list-unassigned-items').append(rowTemplate); }); } } @@ -1481,45 +1426,32 @@ define(function(require){ unassignedNumbers: {} }; - monster.pub('common.numbers.getListFeatures', function(features) { - _.each(data.numbers.numbers, function(number, id) { - /* Formating number */ - number.viewFeatures = $.extend(true, {}, features); - /* TODO: Once locality is enabled, we need to remove it */ - number.localityEnabled = 'locality' in number ? true : false; - - _.each(number.features, function(feature) { - if(feature in number.viewFeatures) { - number.viewFeatures[feature].active = 'active'; - } - }); + _.each(data.numbers.numbers, function(number, id) { + /* TODO: Once locality is enabled, we need to remove it */ + number.localityEnabled = 'locality' in number ? true : false; - monster.util.populateBooleansNumberFeatures(number); - number.extra.hasFeatures = number.extra.hasE911 || number.extra.hasPrepend || number.extra.hasCnam; + if(!number.hasOwnProperty('used_by') || number.used_by === '') { + response.unassignedNumbers[id] = number; + response.countSpare++; + } + }); - if(!number.hasOwnProperty('used_by') || number.used_by === '') { - response.unassignedNumbers[id] = number; - response.countSpare++; + if('groupCallflow' in data.callflow && 'numbers' in data.callflow.groupCallflow) { + _.each(data.callflow.groupCallflow.numbers, function(number) { + if(!(number in data.numbers.numbers)) { + response.extensions.push(number); + } + else { + data.numbers.numbers[number].isLocal = data.numbers.numbers[number].features.indexOf('local') > -1; + response.assignedNumbers[number] = data.numbers.numbers[number]; } }); + } + response.emptyExtensions = _.isEmpty(response.extensions); + response.emptyAssigned = _.isEmpty(response.assignedNumbers); + response.emptySpare = _.isEmpty(response.unassignedNumbers); - if('groupCallflow' in data.callflow && 'numbers' in data.callflow.groupCallflow) { - _.each(data.callflow.groupCallflow.numbers, function(number) { - if(!(number in data.numbers.numbers)) { - response.extensions.push(number); - } - else { - data.numbers.numbers[number].isLocal = data.numbers.numbers[number].features.indexOf('local') > -1; - response.assignedNumbers[number] = data.numbers.numbers[number]; - } - }); - } - response.emptyExtensions = _.isEmpty(response.extensions); - response.emptyAssigned = _.isEmpty(response.assignedNumbers); - response.emptySpare = _.isEmpty(response.unassignedNumbers); - - callback && callback(response); - }); + callback && callback(response); }, groupsGetNumbersData: function(groupId, callback) { diff --git a/submodules/myOffice/myOffice.css b/submodules/myOffice/myOffice.css index df9d213..ffabc25 100644 --- a/submodules/myOffice/myOffice.css +++ b/submodules/myOffice/myOffice.css @@ -246,31 +246,13 @@ color: #22a5ff; } #myoffice_container .dashboard-right-content .dashboard-box .dashboard-box-row .row-content .number-list .features > i { - display: none; cursor: inherit; } -#myoffice_container .dashboard-right-content .dashboard-box .dashboard-box-row .row-content .number-list .features > i.active { - display: inline-block; -} #myoffice_container .dashboard-right-content .dashboard-box .dashboard-box-row .row-content .number-list .number-div { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -/*#myoffice_container .dashboard-right-content .dashboard-box .dashboard-box-row.e911-row > div { - line-height: 20px; -} -#myoffice_container .dashboard-right-content .dashboard-box .dashboard-box-row.e911-row .row-title .line1 { - font-size: 24px; - line-height: 24px; -} -#myoffice_container .dashboard-right-content .dashboard-box .dashboard-box-row.e911-row .row-title .line2 { - line-height: 16px; -} -#myoffice_container .dashboard-right-content .dashboard-box .dashboard-box-row.e911-row .row-content { - text-transform: uppercase; - font-size: 12px; -}*/ #myoffice_container .dashboard-right-content .dashboard-box .dashboard-box-row.account-info-box > div { height: 20px; line-height: 20px; diff --git a/submodules/myOffice/myOffice.js b/submodules/myOffice/myOffice.js index e89fb76..5e4b209 100644 --- a/submodules/myOffice/myOffice.js +++ b/submodules/myOffice/myOffice.js @@ -6,7 +6,19 @@ define(function(require){ var app = { - requests: {}, + requests: { + 'google.geocode.address': { + apiRoot: '//maps.googleapis.com/', + url: 'maps/api/geocode/json?address={zipCode}', + verb: 'GET', + generateError: false, + removeHeaders: [ + 'X-Kazoo-Cluster-ID', + 'X-Auth-Token', + 'Content-Type' + ] + } + }, subscribe: { 'voip.myOffice.render': 'myOfficeRender', @@ -283,11 +295,6 @@ define(function(require){ } }); }, - numberFeatures: function(callback) { - monster.pub('common.numbers.getListFeatures', function(features) { - callback(null, features); - }); - }, channels: function(parallelCallback) { self.callApi({ resource: 'channel.list', @@ -534,13 +541,10 @@ define(function(require){ _.each(val.numbers, function(num) { if(num !== '0' && num !== 'undefined' && num !== 'undefinedconf' && num !== 'undefinedfaxing') { var number = { - number: num, - features: $.extend(true, {}, data.numberFeatures) + number: num }; if(num in data.numbers) { - _.each(data.numbers[num].features, function(feature) { - number.features[feature] = $.extend(true, number.features[feature], { active : 'active'}); - }); + number.features = data.numbers[num].features; } data[numberArrayName].push(number); } @@ -916,12 +920,21 @@ define(function(require){ }); emergencyZipcodeInput.on('blur', function() { - $.getJSON('http://www.geonames.org/postalCodeLookupJSON?&country=US&callback=?', { postalcode: $(this).val() }, function(response) { - if (response && response.postalcodes.length && response.postalcodes[0].placeName) { - emergencyCityInput.val(response.postalcodes[0].placeName); - emergencyStateInput.val(response.postalcodes[0].adminName1); - } - }); + var zipCode = $(this).val(); + + if (zipCode) { + self.myOfficeGetAddessFromZipCode({ + data: { + zipCode: zipCode + }, + success: function(results) { + if (!_.isEmpty(results)) { + emergencyCityInput.val(results[0].address_components[1].long_name); + emergencyStateInput.val(results[0].address_components[3].short_name); + } + } + }); + } }); popupTemplate.find('.save').on('click', function() { @@ -1149,6 +1162,21 @@ define(function(require){ callback && callback(savedUser.data); } }); + }, + + myOfficeGetAddessFromZipCode: function(args) { + var self = this; + + monster.request({ + resource: 'google.geocode.address', + data: args.data, + success: function(data, status) { + args.hasOwnProperty('success') && args.success(data.results); + }, + error: function(errorPayload, data, globalHandler) { + args.hasOwnProperty('error') ? args.error() : globalHandler(data, { generateError: true }); + } + }); } }; diff --git a/submodules/strategy/strategy.css b/submodules/strategy/strategy.css index 9b81219..018bd22 100644 --- a/submodules/strategy/strategy.css +++ b/submodules/strategy/strategy.css @@ -134,9 +134,6 @@ #strategy_container .element-container .number-element .features-block .features { margin-right: 45px; } -#strategy_container .element-container .number-element .features-block .features > i { - display: none; -} #strategy_container .element-container .number-element .features-block .features > i.active { display: inline-block; diff --git a/submodules/strategy/strategy.js b/submodules/strategy/strategy.js index bc56276..ef0b268 100644 --- a/submodules/strategy/strategy.js +++ b/submodules/strategy/strategy.js @@ -181,11 +181,6 @@ define(function(require){ callback(null, voicemailBoxes); }); }, - numberFeatures: function(callback) { - monster.pub('common.numbers.getListFeatures', function(features) { - callback(null, features); - }); - }, directories: function (callback) { self.strategyListDirectories(function (directories) { callback(null, directories); @@ -396,20 +391,13 @@ define(function(require){ var ret = { number: { id: val - }, - features: $.extend(true, {}, strategyData.numberFeatures) + } }; if(accountNumbers.hasOwnProperty(val)) { - _.each(accountNumbers[val].features, function(feature) { - ret.features[feature].active = 'active'; - }); ret.number = $.extend(true, accountNumbers[val], ret.number); } - monster.util.populateBooleansNumberFeatures(ret.number); - ret.number.extra.hasFeatures = ret.number.extra.hasE911 || ret.number.extra.hasPrepend || ret.number.extra.hasCnam; - return ret; } }), @@ -417,6 +405,21 @@ define(function(require){ }, template = $(monster.template(self, 'strategy-'+templateName, templateData)); + _.each(templateData.numbers, function(data) { + data.number.phoneNumber = data.number.id; + + var numberDiv = template.find('[data-phonenumber="'+data.number.id+'"]'), + args = { + target: numberDiv.find('.edit-features'), + numberData: data.number, + afterUpdate: function(features) { + monster.ui.paintNumberFeaturesIcon(features, numberDiv.find('.features')); + } + }; + + monster.pub('common.numberFeaturesMenu.render', args); + }); + monster.ui.tooltips(template); container.find('.element-content').empty() @@ -869,83 +872,6 @@ define(function(require){ }); } }); - - if (monster.util.isNumberFeatureEnabled('cnam')) { - container.on('click', '.number-element .callerId-number', function() { - var cnamCell = $(this).parents('.number-element').first(), - phoneNumber = cnamCell.find('.remove-number').data('number'); - - if(phoneNumber) { - var args = { - phoneNumber: phoneNumber, - callbacks: { - success: function(data) { - if('cnam' in data.data && data.data.cnam.display_name) { - cnamCell.find('.features i.feature-outbound_cnam').addClass('active'); - } else { - cnamCell.find('.features i.feature-outbound_cnam').removeClass('active'); - } - - if('cnam' in data.data && data.data.cnam.inbound_lookup) { - cnamCell.find('.features i.feature-inbound_cnam').addClass('active'); - } else { - cnamCell.find('.features i.feature-inbound_cnam').removeClass('active'); - } - } - } - }; - - monster.pub('common.callerId.renderPopup', args); - } - }); - } - - if (monster.util.isNumberFeatureEnabled('e911')) { - container.on('click', '.number-element .e911-number', function() { - var e911Cell = $(this).parents('.number-element').first(), - phoneNumber = e911Cell.find('.remove-number').data('number'); - - if(phoneNumber) { - var args = { - phoneNumber: phoneNumber, - callbacks: { - success: function(data) { - if(!($.isEmptyObject(data.data.e911))) { - e911Cell.find('.features i.feature-e911').addClass('active'); - } - else { - e911Cell.find('.features i.feature-e911').removeClass('active'); - } - } - } - }; - - monster.pub('common.e911.renderPopup', args); - } - }); - } - - container.on('click', '.number-element .prepend-number', function() { - var prependCell = $(this).parents('.number-element').first(), - phoneNumber = prependCell.find('.remove-number').data('number'); - - if(phoneNumber) { - var args = { - phoneNumber: phoneNumber, - callbacks: { - success: function(data) { - if('prepend' in data.data && data.data.prepend.enabled) { - prependCell.find('.features i.feature-prepend').addClass('active'); - } else { - prependCell.find('.features i.feature-prepend').removeClass('active'); - } - } - } - }; - - monster.pub('common.numberPrepend.renderPopup', args); - } - }); }, strategyConfNumBindEvents: function(container, strategyData) { @@ -2277,25 +2203,6 @@ define(function(require){ } }); - // container.on('click', '.number-text', function(e) { - // var $this = $(this); - // $this.parents('.menu-line').addClass('editing'); - // $this.siblings('.number-input').focus(); - // }); - - // container.on('blur', '.number-input', function(e) { - // var $this = $(this); - // $this.parents('.menu-line').removeClass('editing'); - // $this.siblings('.number-text').text($this.val() || "?"); - // }); - - // container.on('keyup', '.number-input', function(e) { - // var $this = $(this); - // if(!/^[0-9#*]*$/.test($this.val())) { - // $this.val($this.val().replace(/[^0-9#*]/g, "")); - // } - // }); - container.on('change', '.target-select', function(e) { var $this = $(this), iconElem = $this.parents('.target-input').find('.target-icon'), diff --git a/submodules/users/fixtures/resendInstructions.json b/submodules/users/fixtures/resendInstructions.json deleted file mode 100644 index 2c63c08..0000000 --- a/submodules/users/fixtures/resendInstructions.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/submodules/users/fixtures/resetPassword.json b/submodules/users/fixtures/resetPassword.json deleted file mode 100644 index 2c63c08..0000000 --- a/submodules/users/fixtures/resetPassword.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/submodules/users/users.css b/submodules/users/users.css index cfdb99e..c549f3a 100644 --- a/submodules/users/users.css +++ b/submodules/users/users.css @@ -443,14 +443,6 @@ white-space:pre-wrap; } -#users_container .detail-numbers .list-wrapper .item-row .features > i { - display: none; -} - -#users_container .detail-numbers .list-wrapper .item-row .features > i.active { - display: inline-block; -} - #users_container .detail-numbers .list-wrapper .item-row .locality { display: none; border-left: 1px solid #CCC; diff --git a/submodules/users/users.js b/submodules/users/users.js index e662ee8..a2191b8 100644 --- a/submodules/users/users.js +++ b/submodules/users/users.js @@ -428,9 +428,10 @@ define(function(require){ monster.ui.tooltips(dialogTemplate); dialogTemplate.find('#confirm_button').on('click', function() { - var removeDevices = dialogTemplate.find('#delete_devices').is(':checked'); + var removeDevices = dialogTemplate.find('#delete_devices').is(':checked'), + removeConferences = dialogTemplate.find('#delete_conferences').is(':checked'); - self.usersDelete(user.id, removeDevices, function(data) { + self.usersDelete(user.id, removeDevices, removeConferences, function(data) { popup.dialog('close').remove(); callback && callback(data); @@ -649,6 +650,9 @@ define(function(require){ var dataForm = monster.ui.getFormData('form_user_creation'), formattedData = self.usersFormatCreationData(dataForm); + $(this) + .prop({ disabled: 'true' }); + self.usersCreate(formattedData, function(data) { popup.dialog('close').remove(); @@ -1116,14 +1120,23 @@ define(function(require){ template.find('.empty-row').hide(); _.each(numberList, function(val, idx) { - val.isLocal = val.features.indexOf('local') > -1; - template .find('.list-assigned-items') .append($(monster.template(self, 'users-numbersItemRow', { number: val }))); + var numberDiv = template.find('[data-id="'+val.phoneNumber+'"]'), + args = { + target: numberDiv.find('.edit-features'), + numberData: val, + afterUpdate: function(features) { + monster.ui.paintNumberFeaturesIcon(features, numberDiv.find('.features')); + } + }; + + monster.pub('common.numberFeaturesMenu.render', args); + extraSpareNumbers = _.without(extraSpareNumbers, val.phoneNumber); }); @@ -1145,23 +1158,26 @@ define(function(require){ searchType: $(this).data('type'), callbacks: { success: function(numbers) { - monster.pub('common.numbers.getListFeatures', function(features) { - _.each(numbers, function(number, k) { - number.viewFeatures = $.extend(true, {}, features); - number.phoneNumber = number.id; - - monster.util.populateBooleansNumberFeatures(number); - number.extra.hasFeatures = number.extra.hasE911 || number.extra.hasPrepend || number.extra.hasCnam; + _.each(numbers, function(number, k) { + number.phoneNumber = number.id; - var rowTemplate = $(monster.template(self, 'users-numbersItemRow', { + var rowTemplate = $(monster.template(self, 'users-numbersItemRow', { number: number - })); + })), + argsFeatures = { + target: rowTemplate.find('.edit-features'), + numberData: number, + afterUpdate: function(features) { + monster.ui.paintNumberFeaturesIcon(features, rowTemplate.find('.features')); + } + }; - monster.ui.tooltips(rowTemplate); + monster.pub('common.numberFeaturesMenu.render', argsFeatures); - template.find('.list-assigned-items .empty-row').hide(); - template.find('.list-assigned-items').append(rowTemplate); - }); + monster.ui.tooltips(rowTemplate); + + template.find('.list-assigned-items .empty-row').hide(); + template.find('.list-assigned-items').append(rowTemplate); }); } } @@ -1214,83 +1230,6 @@ define(function(require){ } }); - if (monster.util.isNumberFeatureEnabled('cnam')) { - template.on('click', '.callerId-number', function() { - var cnamCell = $(this).parents('.item-row').first(), - phoneNumber = cnamCell.data('id'); - - if(phoneNumber) { - var args = { - phoneNumber: phoneNumber, - callbacks: { - success: function(data) { - if('cnam' in data.data && data.data.cnam.display_name) { - cnamCell.find('.features i.feature-outbound_cnam').addClass('active'); - } else { - cnamCell.find('.features i.feature-outbound_cnam').removeClass('active'); - } - - if('cnam' in data.data && data.data.cnam.inbound_lookup) { - cnamCell.find('.features i.feature-inbound_cnam').addClass('active'); - } else { - cnamCell.find('.features i.feature-inbound_cnam').removeClass('active'); - } - } - } - }; - - monster.pub('common.callerId.renderPopup', args); - } - }); - } - - if (monster.util.isNumberFeatureEnabled('e911')) { - template.on('click', '.e911-number', function() { - var e911Cell = $(this).parents('.item-row').first(), - phoneNumber = e911Cell.data('id'); - - if(phoneNumber) { - var args = { - phoneNumber: phoneNumber, - callbacks: { - success: function(data) { - if(!($.isEmptyObject(data.data.e911))) { - e911Cell.find('.features i.feature-e911').addClass('active'); - } - else { - e911Cell.find('.features i.feature-e911').removeClass('active'); - } - } - } - }; - - monster.pub('common.e911.renderPopup', args); - } - }); - } - - template.on('click', '.prepend-number', function() { - var prependCell = $(this).parents('.item-row').first(), - phoneNumber = prependCell.data('id'); - - if(phoneNumber) { - var args = { - phoneNumber: phoneNumber, - callbacks: { - success: function(data) { - if('prepend' in data.data && data.data.prepend.enabled) { - prependCell.find('.features i.feature-prepend').addClass('active'); - } else { - prependCell.find('.features i.feature-prepend').removeClass('active'); - } - } - } - }; - - monster.pub('common.numberPrepend.renderPopup', args); - } - }); - template.on('click', '.feature[data-feature="caller_id"]', function() { self.usersRenderCallerId(currentUser); }); @@ -2730,6 +2669,19 @@ define(function(require){ self.usersFormatNumbersData(userId, results, function(results) { template = $(monster.template(self, 'users-numbers', results)); + _.each(results.assignedNumbers, function(number) { + var numberDiv = template.find('[data-id="' + number.phoneNumber + '"]'), + argsFeatures = { + target: numberDiv.find('.edit-features'), + numberData: number, + afterUpdate: function(features) { + monster.ui.paintNumberFeaturesIcon(features, numberDiv.find('.features')); + } + }; + + monster.pub('common.numberFeaturesMenu.render', argsFeatures); + }); + callback && callback(template, results); }); }, true); @@ -2808,83 +2760,70 @@ define(function(require){ }); } - monster.pub('common.numbers.getListFeatures', function(features) { - if('numbers' in data.numbers) { - _.each(data.numbers.numbers, function(number, k) { - /* Formating number */ - number.viewFeatures = $.extend(true, {}, features); - /* TODO: Once locality is enabled, we need to remove it */ - number.localityEnabled = 'locality' in number ? true : false; - - _.each(number.features, function(feature) { - if(feature in number.viewFeatures) { - number.viewFeatures[feature].active = 'active'; - } - }); - - monster.util.populateBooleansNumberFeatures(number); - number.extra.hasFeatures = number.extra.hasE911 || number.extra.hasPrepend || number.extra.hasCnam; + if('numbers' in data.numbers) { + _.each(data.numbers.numbers, function(number, k) { + /* TODO: Once locality is enabled, we need to remove it */ + number.localityEnabled = 'locality' in number ? true : false; - /* Adding to spare numbers */ - if(!number.hasOwnProperty('used_by') || number.used_by === '') { - response.countSpare++; - response.unassignedNumbers[k] = number; - } - else if (number.used_by === 'mobile') { - response.assignedNumbers.push(number); - } - }); - } + /* Adding to spare numbers */ + if(!number.hasOwnProperty('used_by') || number.used_by === '') { + response.countSpare++; + response.unassignedNumbers[k] = number; + } + else if (number.used_by === 'mobile') { + response.assignedNumbers.push(number); + } + }); + } - if(response.callflow) { - /* If a number is in a callflow and is returned by the phone_numbers, add it to the assigned numbers */ - _.each(response.callflow.numbers, function(number) { - if(number in data.numbers.numbers) { - var numberElement = data.numbers.numbers[number]; - numberElement.phoneNumber = number; - numberElement.isLocal = numberElement.features.indexOf('local') > -1; + if(response.callflow) { + /* If a number is in a callflow and is returned by the phone_numbers, add it to the assigned numbers */ + _.each(response.callflow.numbers, function(number) { + if(number in data.numbers.numbers) { + var numberElement = data.numbers.numbers[number]; + numberElement.phoneNumber = number; + numberElement.isLocal = numberElement.features.indexOf('local') > -1; - response.assignedNumbers.push(numberElement); - } - else { - response.extensions.push(number); - } - }); - } + response.assignedNumbers.push(numberElement); + } + else { + response.extensions.push(number); + } + }); + } - response.assignedNumbers = monster.util.sort(response.assignedNumbers, 'phoneNumber'); + response.assignedNumbers = monster.util.sort(response.assignedNumbers, 'phoneNumber'); - /* List of extensions */ - response.allExtensions = []; + /* List of extensions */ + response.allExtensions = []; - _.each(data.callflow.list, function(callflow) { - _.each(callflow.numbers, function(number) { - /* If it's a valid extension number (ie: a number that's not in the number database) */ - if(!(number in data.numbers.numbers) && !(_.isNaN(parseInt(number)))) { - response.allExtensions.push(number); - } - }); + _.each(data.callflow.list, function(callflow) { + _.each(callflow.numbers, function(number) { + /* If it's a valid extension number (ie: a number that's not in the number database) */ + if(!(number in data.numbers.numbers) && !(_.isNaN(parseInt(number)))) { + response.allExtensions.push(number); + } }); + }); - /* Sort extensions so that we can recommend an available extension to a user whom would add a new one */ - response.allExtensions.sort(function(a, b) { - var parsedA = parseInt(a), - parsedB = parseInt(b), - result = -1; + /* Sort extensions so that we can recommend an available extension to a user whom would add a new one */ + response.allExtensions.sort(function(a, b) { + var parsedA = parseInt(a), + parsedB = parseInt(b), + result = -1; - if(parsedA > 0 && parsedB > 0) { - result = parsedA > parsedB; - } + if(parsedA > 0 && parsedB > 0) { + result = parsedA > parsedB; + } - return result; - }); + return result; + }); - response.emptyAssigned = _.isEmpty(response.assignedNumbers); - response.emptySpare = _.isEmpty(response.unassignedNumbers); - response.emptyExtensions = _.isEmpty(response.extensions); + response.emptyAssigned = _.isEmpty(response.assignedNumbers); + response.emptySpare = _.isEmpty(response.unassignedNumbers); + response.emptyExtensions = _.isEmpty(response.extensions); - callback && callback(response); - }); + callback && callback(response); }, usersFormatCreationData: function(data, callback) { @@ -2935,7 +2874,7 @@ define(function(require){ }, /* Utils */ - usersDelete: function(userId, removeDevices, callback) { + usersDelete: function(userId, removeDevices, removeConferences, callback) { var self = this; monster.parallel({ @@ -2953,6 +2892,11 @@ define(function(require){ self.usersListCallflowsUser(userId, function(data) { callback(null, data); }); + }, + conferences: function(callback) { + self.usersListConferences(userId, function(data) { + callback(null, data); + }); } }, function(error, results) { @@ -2973,6 +2917,12 @@ define(function(require){ }); }); + listFnDelete.push(function(callback) { + self.usersRemoveBulkConferences(results.conferences, removeConferences, function() { + callback(null, ''); + }); + }); + _.each(results.callflows, function(callflow) { /* @@ -3758,6 +3708,19 @@ define(function(require){ }); }, + usersUnassignConference: function(conferenceId, callback) { + var self = this; + + self.usersGetConference(conferenceId, function(conference) { + conference.name = 'Unassigned ' + conference.name; + delete conference.owner_id; + + self.usersUpdateConference(conference, function(conference) { + callback && callback(conference); + }); + }); + }, + usersUpdateConference: function(conference, callback) { var self = this; @@ -4209,6 +4172,8 @@ define(function(require){ conference_numbers: [] }; + monster.util.dataFlags.add({ source: 'smartpbx'}, baseConference); + baseConference = $.extend(true, {}, baseConference, data.conference); self.usersListConferences(data.user.id, function(conferences) { @@ -4360,24 +4325,38 @@ define(function(require){ } }, + usersRemoveBulkConferences: function(conferences, forceDelete, callback) { + var self = this, + listRequests = []; + + _.each(conferences, function(conference) { + listRequests.push(function(subCallback) { + if(forceDelete) { + self.usersDeleteConference(conference.id, function(data) { + subCallback(null, data); + }); + } + else { + self.usersUnassignConference(conference.id, function(data) { + subCallback(null, data); + }); + } + }); + }); + + monster.parallel(listRequests, function(err, results) { + callback && callback(results); + }); + }, + usersDeleteConferencing: function(userId, globalCallback) { var self = this; monster.parallel({ conferences: function(callback) { self.usersListConferences(userId, function(conferences) { - var listRequests = []; - - _.each(conferences, function(conference) { - listRequests.push(function(subCallback) { - self.usersDeleteConference(conference.id, function(data) { - subCallback(null, data); - }); - }); - }); - - monster.parallel(listRequests, function(err, results) { - callback && callback(results); + self.usersRemoveBulkConferences(conferences, true, function(results) { + callback && callback(null, results); }); }); }, diff --git a/views/devices-sip_device.html b/views/devices-sip_device.html index 5046e75..e9eef14 100644 --- a/views/devices-sip_device.html +++ b/views/devices-sip_device.html @@ -36,9 +36,9 @@
  • {{ i18n.devices.popupSettings.callerId.menuTitle }}
  • {{/if}}
  • {{ i18n.devices.popupSettings.miscellaneous.menuTitle }}
  • - {{#if provision.feature_keys}} -
  • {{ i18n.devices.popupSettings.featureKeys.menuTitle }}
  • - {{/if}} + {{#each extra.provision.keys}} +
  • {{title}}
  • + {{/each}} @@ -263,65 +263,77 @@ {{/if}} - {{#if provision.feature_keys}} -
    + {{#each extra.provision.keys}} +
    - {{ i18n.devices.popupSettings.featureKeys.menuTitle }} + {{{title}}}
    - {{ i18n.devices.popupSettings.featureKeys.info.link.showInfo }} -
    - {{#each extra.featureKeys.types}} -

    {{#if info}}{{text}}: {{info}}{{/if}}

    - {{/each}} + + + + {{ @root.i18n.devices.popupSettings.keys.info.link.showInfo }} + + +
    + {{#each @root.extra.provision.keyActions}} + {{#if info}} +

    + + {{text}} + + : {{info}} +

    + {{/if}} + {{/each}}
    - {{#each provision.feature_keys}} + {{#each data}}
    -
    - {{/each}} + {{/each}}
    - {{/if}} + {{/each}}
    diff --git a/views/groups-numbers.html b/views/groups-numbers.html index 97889c7..8801cc1 100644 --- a/views/groups-numbers.html +++ b/views/groups-numbers.html @@ -7,35 +7,12 @@ {{#each assignedNumbers}}
    -
    - {{#if this.extra.hasFeatures}} - - {{/if}} -
    +
    - {{#compare this.state '===' 'port_in'}} - - {{/compare}} - {{#each viewFeatures}} - - {{/each}} + {{#numberFeatures this.features}}{{/numberFeatures}} + {{#compare state '===' 'port_in'}} + + {{/compare}}
    diff --git a/views/groups-numbersItemRow.html b/views/groups-numbersItemRow.html index 221f347..966d84e 100644 --- a/views/groups-numbersItemRow.html +++ b/views/groups-numbersItemRow.html @@ -1,34 +1,12 @@
    -
    - {{#if number.extra.hasFeatures}} - - {{/if}} -
    +
    +
    - {{#compare number.state '===' 'port_in'}} + {{#numberFeatures number.features}}{{/numberFeatures}} + {{#compare number.state '===' 'port_in'}} - {{/compare}} - {{#each number.viewFeatures}} - - {{/each}} + {{/compare}}
    diff --git a/views/myOffice-layout.html b/views/myOffice-layout.html index 52b1c5a..bd25a92 100644 --- a/views/myOffice-layout.html +++ b/views/myOffice-layout.html @@ -87,9 +87,7 @@ {{#each mainNumbers}}
    - {{#each this.features}} - - {{/each}} + {{#numberFeatures this.features}}{{/numberFeatures}}
    {{formatPhoneNumber this.number}}
    @@ -113,9 +111,7 @@ {{#each confNumbers}}
  • - {{#each this.features}} - - {{/each}} + {{#numberFeatures this.features}}{{/numberFeatures}}
    {{formatPhoneNumber number}}
  • @@ -134,9 +130,7 @@ {{#each faxingNumbers}}
  • - {{#each this.features}} - - {{/each}} + {{#numberFeatures this.features}}{{/numberFeatures}}
    {{formatPhoneNumber number}}
  • diff --git a/views/strategy-numbers.html b/views/strategy-numbers.html index 6f24ed5..cc289c3 100644 --- a/views/strategy-numbers.html +++ b/views/strategy-numbers.html @@ -1,59 +1,39 @@ -{{#each numbers}} -
    -
    - - {{formatPhoneNumber this.number.id}} -
    -
    -
    - {{#if this.number.extra.hasFeatures}} -