Browse Source

UI-2057: Expose combo keys for editing if available and make it easy to add other types of keys

4.3
Joris Tirado 9 years ago
parent
commit
0946face5a
3 changed files with 205 additions and 86 deletions
  1. +9
    -3
      i18n/en-US.json
  2. +155
    -54
      submodules/devices/devices.js
  3. +41
    -29
      views/devices-sip_device.html

+ 9
- 3
i18n/en-US.json View File

@ -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",


+ 155
- 54
submodules/devices/devices.js View File

@ -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,20 +180,28 @@ 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 = {};
}
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 keyTypes = self.getKeyTypes(template);
if (keyTypes) {
self.devicesListUsers({
success: function(users) {
var keyTypes = [ 'none', 'presence', 'parking', 'personal_parking', 'speed_dial' ],
_.each(keyTypes, function(type, idx) {
if (!dataDevice.provision.hasOwnProperty(type)) {
dataDevice.provision[type] = {};
}
var i = 0,
len = template[type].iterate;
for (; i < len; i++) {
if (!dataDevice.provision[type].hasOwnProperty(i)) {
dataDevice.provision[type][i] = {
type: 'none'
}
}
}
});
var actions = [ 'none', 'presence', 'parking', 'personal_parking', 'speed_dial' ],
parkingSpots = [],
extra;
@ -191,28 +213,100 @@ 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: users,
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);
}
});
}
// if (template.hasOwnProperty('feature_keys') && template.feature_keys.iterate > 0) {
// if (!dataDevice.provision.hasOwnProperty('feature_keys')) {
// dataDevice.provision.feature_keys = {};
// }
// 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' };
// }
// }
// self.callApi({
// resource: 'user.list',
// data: {
// accountId: self.accountId
// },
// success: function(data, status) {
// var keyTypes = [ 'none', 'presence', 'parking', 'personal_parking', 'speed_dial' ],
// parkingSpots = [],
// extra;
// // Sort user list by last name
// data.data.sort(function(a, b) {
// return a.last_name.toLowerCase() > b.last_name.toLowerCase() ? 1 : -1;
// });
// // Generate parking spots map
// for (var i = 0; i < 10; i++) {
// parkingSpots[i] = i + 1;
// }
// keyTypes.forEach(function(val, idx, arr) {
// arr[idx] = {
// id: val,
// text: self.i18n.active().devices.popupSettings.keys.types[val]
// };
// if (val !== 'none') {
// arr[idx].info = self.i18n.active().devices.popupSettings.keys.info.types[val];
// }
// });
// extra = {
// users: data.data,
// featureKeys:{
// parkingSpots: parkingSpots,
// types: keyTypes
// }
// };
// dataDevice.extra = dataDevice.hasOwnProperty('extra') ? $.extend(true, {}, dataDevice.extra, extra) : extra;
// self.devicesRenderDevice(dataDevice, callbackSave, callbackDelete);
// }
// });
// }
else {
self.devicesRenderDevice(dataDevice, callbackSave, callbackDelete);
}
@ -275,23 +369,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.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 ) {
@ -511,7 +610,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]);
});
});
@ -609,18 +708,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);
@ -658,19 +768,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;
@ -942,6 +1039,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;


+ 41
- 29
views/devices-sip_device.html View File

@ -36,9 +36,9 @@
<li><a class="tabs-selector change-section" data-section="callerId" href="javascript:void(0)"><i class="fa fa-ambulance"></i>{{ i18n.devices.popupSettings.callerId.menuTitle }}</a></li>
{{/if}}
<li><a class="tabs-selector change-section" data-section="miscellaneous" href="javascript:void(0)"><i class="fa fa-cogs"></i>{{ i18n.devices.popupSettings.miscellaneous.menuTitle }}</a></li>
{{#if provision.feature_keys}}
<li><a class="tabs-selector change-section" data-section="featureKeys" href="javascript:void(0);"><i class="fa fa-lightbulb-o"></i>{{ i18n.devices.popupSettings.featureKeys.menuTitle }}</a></li>
{{/if}}
{{#each extra.provision.keys}}
<li><a class="tabs-selector change-section" data-section="{{type}}" href="javascript:void(0);"><i class="fa fa-lightbulb-o"></i>{{title}}</a></li>
{{/each}}
</ul>
</li>
</ul>
@ -263,65 +263,77 @@
{{/if}}
</div>
{{#if provision.feature_keys}}
<div class="tabs-section clearfix" data-section="featureKeys">
{{#each extra.provision.keys}}
<div class="tabs-section clearfix keys" data-section="{{type}}">
<div class="title">
{{ i18n.devices.popupSettings.featureKeys.menuTitle }}
{{{title}}}
</div>
<div class="type-info helper">
<a href="javascript:void(0);" data-toggle="collapse" data-target="#info_content"><i class="fa fa-question-circle"></i><span class="text">{{ i18n.devices.popupSettings.featureKeys.info.link.showInfo }}</span></a>
<div id="info_content" class="collapse">
{{#each extra.featureKeys.types}}
<p>{{#if info}}<strong>{{text}}</strong>: {{info}}{{/if}}</p>
{{/each}}
<a href="javascript:void(0);" data-toggle="collapse" data-target="#info_content_{{type}}">
<i class="fa fa-question-circle"></i>
<span class="text">
{{ @root.i18n.devices.popupSettings.keys.info.link.showInfo }}
</span>
</a>
<div id="info_content_{{type}}" class="collapse">
{{#each @root.extra.provision.keyActions}}
{{#if info}}
<p>
<strong>
{{text}}
</strong>
: {{info}}
</p>
{{/if}}
{{/each}}
</div>
</div>
{{#each provision.feature_keys}}
{{#each data}}
<div class="control-group" data-id="{{@key}}">
<label for="provision.feature_keys[{{@key}}].type" class="control-label">
{{ @root.i18n.devices.popupSettings.featureKeys.description }} <span class="feature-key-index">{{@key}}</span>
<label for="provision.keys.{{../id}}[{{@key}}].type" class="control-label">
{{ ../label }} <span class="feature-key-index">{{@key}}</span>
</label>
<div class="controls">
<select name="provision.feature_keys[{{@key}}].type" class="feature-key-type span2">
<select name="provision.keys.{{../id}}[{{@key}}].type" class="feature-key-type span2">
{{#select type}}
{{#each ../extra.featureKeys.types}}
{{#each @root.extra.provision.keyActions}}
<option value="{{id}}">{{text}}</option>
{{/each}}
{{/select}}
</select>
<div class="feature-key-value" data-type="presence">
<label for="provision.feature_keys[{{@key}}].value">{{ @root.i18n.devices.popupSettings.featureKeys.labels.user }}</label>
<select name="provision.feature_keys[{{@key}}].value" class="chosen-feature-key-user">
{{#each ../extra.users}}
<label for="provision.keys.{{../id}}[{{@key}}].value">{{ @root.i18n.devices.popupSettings.keys.labels.user }}</label>
<select name="provision.keys.{{../id}}[{{@key}}].value" class="chosen-feature-key-user">
{{#each @root.extra.provision.users}}
<option value="{{id}}">{{first_name}} {{last_name}}</option>
{{/each}}
</select>
</div>
<div class="feature-key-value" data-type="parking">
<label for="provision.feature_keys[{{@key}}].value">{{ @root.i18n.devices.popupSettings.featureKeys.labels.parkingSpot }}</label>
<select class="span1" name="provision.feature_keys[{{@key}}].value">
{{#each ../extra.featureKeys.parkingSpots}}
<label for="provision.keys.{{../id}}[{{@key}}].value">{{ @root.i18n.devices.popupSettings.keys.labels.parkingSpot }}</label>
<select class="span1" name="provision.keys.{{../id}}[{{@key}}].value">
{{#each @root.extra.provision.parkingSpots}}
<option value="{{this}}">{{this}}</option>
{{/each}}
</select>
</div>
<div class="feature-key-value" data-type="personal_parking">
<label for="provision.feature_keys[{{@key}}].value">{{ @root.i18n.devices.popupSettings.featureKeys.labels.user }}</label>
<select name="provision.feature_keys[{{@key}}].value" class="chosen-feature-key-user">
{{#each ../extra.users}}
<label for="provision.keys.{{../id}}[{{@key}}].value">{{ @root.i18n.devices.popupSettings.keys.labels.user }}</label>
<select name="provision.keys.{{../id}}[{{@key}}].value" class="chosen-feature-key-user">
{{#each @root.extra.provision.users}}
<option value="{{id}}">{{first_name}} {{last_name}}</option>
{{/each}}
</select>
</div>
<div class="feature-key-value" data-type="speed_dial">
<label for="provision.feature_keys[{{@key}}].value">{{ @root.i18n.devices.popupSettings.featureKeys.labels.value }}</label>
<input type="text" value="" name="provision.feature_keys[{{@key}}].value">
<label for="provision.keys.{{../id}}[{{@key}}].value">{{ @root.i18n.devices.popupSettings.keys.labels.value }}</label>
<input type="text" value="" name="provision.keys.{{../id}}[{{@key}}].value">
</div>
</div>
</div>
{{/each}}
{{/each}}
</div>
{{/if}}
{{/each}}
</form>
</div>


Loading…
Cancel
Save