TT#11852 ngcp-csc Pbx Devices

Change-Id: I12d7cec5f238c78ca6f300bbc017c3d31e5f3e6d
changes/81/12481/9
Carlo 9 years ago
parent 1f64b97a60
commit 4f3b4207ef

@ -7,17 +7,84 @@ Ext.define('NgcpCsc.model.Device', {
}, {
name: 'device',
type: 'string'
},{
}, {
name: 'mac',
type: 'string'
},{
name: 'status',
type: 'string'
}, {
name: 'image',
type: 'string'
}, {
name: 'destinations',
name: 'image',
type: 'string'
},{
name: 'image',
type: 'string'
},{
name: 'seats',
type: 'auto'
}, {
name: 'imageWithButtons',
depends: ['image'],
persist: false,
convert: function(v, rec) {
var retVal = "<div><img width=500 height=500 src='" + rec.get('image') + "'></div>";
var shiftPosition = false;
Ext.each(rec.get('seats'), function(seat) {
if (seat.name) {
var buttonCls = 'assigned-button';
var btnPos = "top:" + seat.position.top + ";left:" + seat.position.left;
var rectPos,
top = seat.position.top,
left = seat.position.left,
lineWidth = shiftPosition ? "35%" : "20%",
lineHeight = shiftPosition ? "18%" : "10%",
lineTop = top,
lineLeft = seat.position.left,
lineCls = seat.position.anchor == 'left' || seat.position.anchor == 'right' ? 'connection-left-right' : 'connection-top-bottom';
switch (seat.position.anchor) {
case "left":
lineHeight = "1%";
left = (parseInt(seat.position.left.split('%')[0]) + (shiftPosition ? 30 : 10)).toString() + "%";
top = (parseInt(seat.position.top.split('%')[0]) - 1).toString() + "%";
break;
case "right":
left = (parseInt(seat.position.left.split('%')[0]) - (shiftPosition ? 35 : 20)).toString() + "%";
top = (parseInt(seat.position.top.split('%')[0]) - 1).toString() + "%";
lineLeft = left;
lineHeight = "1%";
break;
case "top":
lineLeft = (parseInt(seat.position.left.split('%')[0]) + 1).toString() + "%";
top = (parseInt(seat.position.top.split('%')[0]) + (shiftPosition ? 14 : 7)).toString() + "%";
break;
case "bottom":
lineLeft = (parseInt(seat.position.left.split('%')[0]) + 1).toString() + "%";
top = (parseInt(seat.position.top.split('%')[0]) - (shiftPosition ? 14 : 7)).toString() + "%";
break;
}
retVal += '<div><span data-qtip="'+Ngcp.csc.locales.pbxconfig.devices.tooltip.click[localStorage.getItem('languageSelected')]+'" data-onseathovered="seatHovered" data-onseatclick="seatClick" class="button-info pointer card-icon" style="top:' +
top + ';left:' + left + ';" id="seat-info' +
rec.get('id') + "-" + seat.order + '">' +
seat.order + ' | ' + seat.name + '</span><span class="' +
lineCls + '" style="height:' + lineHeight + ';width:' +
lineWidth + ';top:' + lineTop + ';left:' +
lineLeft + ';"></span><span id="seat-"' +
rec.get('id') + "-" + seat.order + '" class="' +
buttonCls + '" style="' +
btnPos + '"></span></div>';
} else {
var top = (parseInt(seat.position.top.split('%')[0]) - 0.5).toString() + "%";
var btnPos = "top:" + top + ";left:" + seat.position.left;
var buttonCls = 'free-button';
retVal += '<div data-qtip="'+Ngcp.csc.locales.pbxconfig.devices.tooltip.clicktoassign[localStorage.getItem('languageSelected')]+'" data-onseathovered="seatHovered" data-onseatclick="seatClick" id="seat-' +rec.get('id') + '-' + seat.order + '" class="' +
buttonCls + ' pointer card-icon" style="' +
btnPos + '"></div>';
}
shiftPosition = !shiftPosition;
});
return retVal;
}
}]
});

@ -7,5 +7,11 @@ Ext.define('NgcpCsc.model.DevicesListItem', {
}, {
name: 'name',
type: 'string'
},{
name: 'img',
type: 'string'
},{
name: 'destinations',
type: 'auto'
}]
});

@ -1541,11 +1541,11 @@ Ext.define('Ngcp.csc.locales', {
sp: 'ADD NEW DEVICE'
},
device: {
en: 'Device',
it: 'Device',
de: 'Device',
fr: 'Device',
sp: 'Device'
en: 'Phone Model:',
it: 'Phone Model:',
de: 'Phone Model:',
fr: 'Phone Model:',
sp: 'Phone Model:'
},
device_profile: {
en: 'Device profile',
@ -1562,11 +1562,11 @@ Ext.define('Ngcp.csc.locales', {
sp: 'Destination'
},
extension: {
en: 'Extension:',
it: 'Extension:',
de: 'Extension:',
fr: 'Extension:',
sp: 'Extension:'
en: 'Extension',
it: 'Extension',
de: 'Extension',
fr: 'Extension',
sp: 'Extension'
},
mac: {
en: 'Mac address:',
@ -1631,6 +1631,13 @@ Ext.define('Ngcp.csc.locales', {
fr: 'Name:',
sp: 'Name:'
},
station_name: {
en: 'Station name:',
it: 'Station name:',
de: 'Station name:',
fr: 'Station name:',
sp: 'Station name:'
},
enter_new_name: {
en: 'Enter new name',
it: 'Enter new name',
@ -1701,6 +1708,13 @@ Ext.define('Ngcp.csc.locales', {
fr: 'Enter new status',
sp: 'Enter new status'
},
enter_new_extension: {
en: 'Enter new extension',
it: 'Enter new extension',
de: 'Enter new extension',
fr: 'Enter new extension',
sp: 'Enter new extension'
},
cancel_operation: {
en: 'Cancel operation',
it: 'Cancel operation',
@ -1786,6 +1800,32 @@ Ext.define('Ngcp.csc.locales', {
fr: 'Auto attendants for ',
sp: 'Auto attendants for '
}
},
devices: {
delete_assignment:{
en: 'Do you really want to unassign button {0}?',
it: 'Do you really want to unassign button {0}?',
de: 'Do you really want to unassign button {0}?',
fr: 'Do you really want to unassign button {0}?',
sp: 'Do you really want to unassign button {0}?'
},
tooltip:{
click: {
en: 'Click to edit or remove',
it: 'Click to edit or remove',
de: 'Click to edit or remove',
fr: 'Click to edit or remove',
sp: 'Click to edit or remove'
},
clicktoassign: {
en: 'Click to assign',
it: 'Click to assign',
de: 'Click to assign',
fr: 'Click to assign',
sp: 'Click to assign'
},
}
}
},
common: {

@ -49,26 +49,6 @@ $grid-row-cell-focus-border-color: '#fff';
width: 100%;
color: $base-color;
.img-row {
position:relative;
padding: 20;
img {
width: 100%;
}
.number-circle {
position:absolute;
border-radius: 50%;
width: 30px;
height: 30px;
padding: 4px;
background: #fff;
border: 2px solid $base-color;
color: $base-color;
text-align: center;
font-size: 16px;
}
}
.fa {
margin-right: 10px;
color: $base-color;

@ -46,6 +46,8 @@
$row-indicator-over-color: transparent
);
// override of extjs classes to add css variables defined in sass/var/view/main:
.x-form-text-default {
color: var(--color);

@ -0,0 +1,60 @@
.devices {
.x-panel-body {
background: white;
}
.device-img {
display: block;
}
.circle-number {
position:absolute;
border-radius: 50%;
width: 12px;
height: 12px;
border: 2px #fff;
color: #fff;
text-align: center;
font-size: 12px;
}
.assigned-button {
@extend .circle-number;
background: red;
}
.free-button {
@extend .circle-number;
background: yellow;
}
.button-info {
position: absolute;
background: white;
border: 1px solid red;
padding: 0px 5px 0 5px;
z-index: 1;
min-width: 60px;
font-size: 11px;
}
.connection-left-right {
margin-top: 5px;
position: absolute;
border-top: 1px solid red;
background-color:rgba(255,0,0,0);
}
.connection-top-bottom {
position: absolute;
border-left: 1px solid red;
background-color:rgba(255,0,0,0);
}
.edit-panel {
background: #F6F6F6;
}
.seat-name {
margin-left: 20px;
}
.x-btn-group-default-framed {
border-color: #F6F6F6;
border-width: 0px;
}
.devices-seat-fieldset {
border: 1px solid red !important;
}
}

@ -27,7 +27,6 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfig', {
}]
}]
}];
this.callParent();
}
});

@ -11,7 +11,7 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
}
},
onRouteChange: function () {
onRouteChange: function() {
var vm = this.getViewModel();
switch (window.location.hash) {
case '#pbxconfig/seats':
@ -26,7 +26,7 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
};
},
onEnterPressed: function (field, el) {
onEnterPressed: function(field, el) {
var me = this;
if (el.getKey() == el.ENTER) {
var currentRoute = window.location.hash;
@ -45,7 +45,7 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
};
},
nameRenderer: function (value, record) {
nameRenderer: function(value, record) {
if (value == '') {
return Ngcp.csc.locales.pbxconfig.enter_new_name[localStorage.getItem('languageSelected')];
} else {
@ -74,9 +74,32 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
var store = Ext.getStore(storeName);
var plugin = view.grid.getPlugin('rowwidget' + storeName);
plugin.toggleRow(store.indexOf(record), record);
Ext.defer(function () {
Ext.defer(function() {
view.grid.updateLayout();
}, 50);
if (currentRoute == '#pbxconfig/devices') {
var grid = this.lookupReference('devicesGrid');
var nodes = plugin.view.getNodes();
grid.getSelectionModel().select(record);
store.each(function(rec, index){
var node = Ext.fly(nodes[index]);
if(rec.get('id') !== record.get('id') && node.getHeight() > 50){
plugin.toggleRow(index, store.getAt(index)); // collapse all cards but the active one
}
});
}
},
// Workaround, to prevent row from collapsings
keepRowExpanded: function(grid, rec) {
var currentRoute = window.location.hash;
var storeName = this.getStoreFromRoute(currentRoute);
var plugin = grid.getPlugin('rowwidget' + storeName);
var store = Ext.getStore(storeName);
plugin.toggleRow(store.indexOf(rec), rec);
plugin.toggleRow(store.indexOf(rec), rec);
},
getFieldComponent: function(view, key, id) {
@ -107,9 +130,9 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
var elClassList = el.firstChild.classList;
var recId = el.id.split("-")[1];
var store = Ext.getStore(storeName);
saved === true
? this.fireEvent('showmessage', true, Ngcp.csc.locales.pbxconfig.changes_saved[localStorage.getItem('languageSelected')])
: this.fireEvent('showmessage', false, Ngcp.csc.locales.pbxconfig.no_changes_saved[localStorage.getItem('languageSelected')]);
saved === true ?
this.fireEvent('showmessage', true, Ngcp.csc.locales.pbxconfig.changes_saved[localStorage.getItem('languageSelected')]) :
this.fireEvent('showmessage', false, Ngcp.csc.locales.pbxconfig.no_changes_saved[localStorage.getItem('languageSelected')]);
elClassList.remove(Ngcp.csc.icons.floppy.split(' ')[1]);
elClassList.add(Ngcp.csc.icons.edit.split(' ')[1]);
el.dataset.callback = 'editCard';
@ -127,13 +150,15 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
var rec = store.findRecord('id', recId);
var currentNameInRecord = rec.get("name");
var grid = this.lookupReference(storeName.toLowerCase() + 'Grid');
var plugin = grid.getPlugin('rowwidget' + storeName);
var form = Ext.ComponentQuery.query('#' + storeName.toLowerCase() + '-' + recId)[0];
var formFields = form.query('textfield');
var labels = form.query('label');
var formFields = form.query('textfield, combo');
var invalidCheck = 0;
for (var field in formFields) {
var fieldValue = formFields[field].value;
if (Ext.isEmpty(formFields[field].value)) invalidCheck ++;
if (!formFields[field]._skipSaveValidation && Ext.isEmpty(formFields[field].value)) {
invalidCheck++;
}
};
switch (invalidCheck === 0) {
case true:
@ -147,9 +172,7 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
switch (rec.dirty) {
case true:
store.commitChanges();
// Workaround, to prevent row from collapsing
plugin.toggleRow(store.indexOf(rec), rec);
plugin.toggleRow(store.indexOf(rec), rec);
this.keepRowExpanded(grid, rec);
me.showMsgSwitchIconHideFields(storeName, el, true);
break;
case false:
@ -163,18 +186,41 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
};
},
addNewEmptyRowToGrid: function (store, storeName, newId) {
addNewEmptyRowToGrid: function(store, storeName, newId) {
var newRec;
switch (storeName) {
case 'Seats':
store.add({ "id": newId, "name": "", "extension": "", "group": "", "numbers": "", "phone_devices": "" });
newRec = store.add({
"id": newId,
"name": "",
"extension": "",
"group": "",
"numbers": "",
"phone_devices": ""
});
break;
case 'Groups':
store.add({ "id": newId, "name": "", "extension": "", "hunt_policy": "", "hunt_timeout": "" });
newRec = store.add({
"id": newId,
"name": "",
"extension": "",
"hunt_policy": "",
"hunt_timeout": ""
});
break;
case 'Devices':
store.add({ "id": newId, "name": "", "device": "", "mac": "", "status": "" });
newRec = store.add({
"id": newId,
"name": "",
"device": "",
"mac": "",
"status": "",
"extension":"",
"extension2":""
});
break;
}
this.getView().down('grid').getSelectionModel().select(newRec);
},
addPbx: function() {
@ -188,7 +234,7 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
me.addNewEmptyRowToGrid(store, storeName, newId);
var rec = store.findRecord('id', newId);
plugin.toggleRow(store.indexOf(rec), rec);
Ext.defer(function () {
Ext.defer(function() {
me.showHideFocusFieldsById(newId, storeName, 'show');
var el = document.getElementById('edit' + storeName.slice(0, -1) + '-' + newId);
var elClassList = el.firstChild.classList;
@ -200,14 +246,16 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
}, 50);
},
setFieldValue: function (cmp) {
setFieldValue: function(cmp) {
var recId = cmp.id.split("-")[3];
var recKey = cmp.id.split("-")[2];
var currentRoute = window.location.hash;
var storeName = this.getStoreFromRoute(currentRoute);
var store = Ext.getStore(storeName);
var rec = store.findRecord('id', recId);
cmp.setValue(rec.get(recKey));
if (!cmp.getValue()) {
cmp.setValue(rec.get(recKey));
}
},
showHideFocusFieldsById: function(id, storeName, hideOrShow) {
@ -217,6 +265,7 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
var mainNameLabel = Ext.ComponentQuery.query('#' + viewName + '-label-mainname-' + id) || '';
var nameField = Ext.ComponentQuery.query('#' + viewName + '-textfield-name-' + id) || '';
var extensionField = Ext.ComponentQuery.query('#' + viewName + '-textfield-extension-' + id) || '';
var extensionField2 = Ext.ComponentQuery.query('#' + viewName + '-textfield-extension2-' + id) || '';
var primaryNumberField = Ext.ComponentQuery.query('#' + viewName + '-combo-primary_number-' + id) || '';
var aliasNumbersField = Ext.ComponentQuery.query('#' + viewName + '-tagfield-alias_numbers-' + id) || '';
var groupsField = Ext.ComponentQuery.query('#' + viewName + '-tagfield-groups-' + id) || '';
@ -229,6 +278,7 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
var groupsLabel = Ext.ComponentQuery.query('#' + viewName + '-label-groups-' + id) || '';
var primaryNumberLabel = Ext.ComponentQuery.query('#' + viewName + '-label-primary_number-' + id) || '';
var aliasNumbersLabel = Ext.ComponentQuery.query('#' + viewName + '-label-alias_numbers-' + id) || '';
var extensionLabel2 = Ext.ComponentQuery.query('#' + viewName + '-label-extension2-' + id) || '';
var huntPolicyLabel = Ext.ComponentQuery.query('#' + viewName + '-label-hunt_policy-' + id) || '';
var huntTimeoutLabel = Ext.ComponentQuery.query('#' + viewName + '-label-hunt_timeout-' + id) || '';
var huntTimeoutPreLabel = Ext.ComponentQuery.query('#' + viewName + '-prelabel-hunt_timeout-' + id) || '';
@ -274,14 +324,20 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
case 'devices':
deviceLabel[0].setHidden(labelHide);
macLabel[0].setHidden(labelHide);
statusLabel[0].setHidden(labelHide);
nameField[0].setHidden(fieldHide);
deviceField[0].setHidden(fieldHide);
macField[0].setHidden(fieldHide);
statusField[0].setHidden(fieldHide);
statusField[0].focus();
extensionLabel[0].setHidden(labelHide);
extensionField[0].setHidden(fieldHide);
extensionLabel2[0].setHidden(labelHide);
extensionField2[0].setHidden(fieldHide);
macField[0].focus();
deviceField[0].focus();
nameField[0].focus();
extensionField[0].focus();
extensionField2[0].focus();
Ext.defer(function() {
nameField[0].focus();
}, 100)
break;
};
},
@ -298,7 +354,7 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
elClassList.remove(Ngcp.csc.icons.edit.split(' ')[1]);
elClassList.add(Ngcp.csc.icons.floppy.split(' ')[1]);
el.dataset.callback = 'saveCard';
Ext.defer(function () {
Ext.defer(function() {
me.showHideFocusFieldsById(recId, storeName, 'show');
}, 50);
},
@ -313,7 +369,7 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
this.fireEvent('showmessage', true, Ngcp.csc.locales.common.remove_success[localStorage.getItem('languageSelected')]);
},
toggleCancelCard: function (el, state) {
toggleCancelCard: function(el, state) {
var cancelCardId = el.id.replace(/edit|save/, 'cancel');
var cancelCard = document.getElementById(cancelCardId);
var elClassList = cancelCard.classList;
@ -327,7 +383,7 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.PbxConfigController', {
};
},
cancelCard: function (el, abortAdd) {
cancelCard: function(el, abortAdd) {
var me = this;
var currentRoute = window.location.hash;
var storeName = this.getStoreFromRoute(currentRoute);

@ -2,7 +2,7 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.devices.Devices', {
extend: 'NgcpCsc.view.pages.pbxconfig.PbxConfig',
xtype: 'devices',
controller: 'devices',
initComponent: function() {
var devicesGrid = Ext.create('NgcpCsc.view.pages.pbxconfig.devices.DevicesGrid');

@ -0,0 +1,159 @@
Ext.define('NgcpCsc.view.pages.pbxconfig.DevicseController', {
extend: 'NgcpCsc.view.pages.pbxconfig.PbxConfigController',
alias: 'controller.devices',
onIconClicked: function(event, el) {
// override onIconClicked of PbxConfigController
if (el.dataset.onseatclick) {
Ext.Function.defer(eval('this.' + el.dataset.onseatclick), 1, this, [el]);
return;
};
if (el.dataset.callback) {
Ext.Function.defer(eval('this.' + el.dataset.callback), 1, this, [el]);
};
},
onMouseEntered: function(event, el) {
if (el.dataset.onseathovered) {
Ext.Function.defer(eval('this.' + el.dataset.onseathovered), 1, this, [el]);
}
},
seatHovered: function(el) {
this.setShowEditPanelFields(el);
},
seatClick: function(el) {
this.setShowEditPanelFields(el, true);
},
setShowEditPanelFields: function(el, showBtns) {
var selectedRec = this.getSelectedRec();
var showPanel = Ext.ComponentQuery.query('#seat-show-panel-' + selectedRec.get('id'))[0];
var editPanel = Ext.ComponentQuery.query('#seat-edit-panel-' + selectedRec.get('id'))[0];
var order = el.id.split('-')[2];
var seatData;
Ext.each(selectedRec.get('seats'), function(seat) {
if (order == seat.order) {
seatData = seat;
return;
}
});
showPanel.down('[name=editBtns]').hide();
showPanel.down('[name=typeValue]').setHtml((seatData && seatData.type && seatData.name) ? seatData.type + ": " + seatData.name : "Unassigned");
editPanel._user = seatData.name || null;
editPanel._type = seatData.type || null;
editPanel._order = seatData.order;
showPanel.setTitle(seatData.order);
editPanel.setTitle('Edit ' + seatData.order);
if (showBtns) {
showPanel.down('[name=editBtns]').show();
showPanel.addCls('devices-seat-fieldset');
}else{
showPanel.removeCls('devices-seat-fieldset');
}
editPanel.hide();
showPanel.show();
},
deviceSelected: function(combo, rec) {
var grid = this.lookupReference('devicesGrid');
var devicesListStore = Ext.getStore('DevicesList');
var selectedRec = this.getSelectedRec();
var selectedRecFromList = devicesListStore.findRecord('name', combo.getValue());
var nameField = Ext.ComponentQuery.query('#devices-textfield-name-' + selectedRec.get('id'))[0];
var showPanel = Ext.ComponentQuery.query('#seat-show-panel-' + selectedRec.get('id'))[0];
var editPanel = Ext.ComponentQuery.query('#seat-edit-panel-' + selectedRec.get('id'))[0];
if (selectedRec) {
selectedRec.set('seats', selectedRecFromList.get('seats'))
selectedRec.set('image', selectedRecFromList.get('image'));
selectedRec.set('device', combo.getValue());
}
this.keepRowExpanded(grid, selectedRec);
showPanel.hide();
Ext.Function.defer(function() {
grid.getView().refresh();
nameField.focus();
}, 50)
},
editSeat: function() {
var selectedRec = this.getSelectedRec();
var showPanel = Ext.ComponentQuery.query('#seat-show-panel-' + selectedRec.get('id'))[0];
var editPanel = Ext.ComponentQuery.query('#seat-edit-panel-' + selectedRec.get('id'))[0];
var type = editPanel._type;
var seatName = editPanel._user;
editPanel.down('[name=typeValue]').setValue(type);
editPanel.down('[name=seat]').setValue(seatName);
showPanel.hide();
editPanel.show();
},
deleteSeat: function() {
var me = this;
var selectedRec = this.getSelectedRec();
var showPanel = Ext.ComponentQuery.query('#seat-show-panel-' + selectedRec.get('id'))[0];
var editPanel = Ext.ComponentQuery.query('#seat-edit-panel-' + selectedRec.get('id'))[0];
Ext.each(selectedRec.get('seats'), function(seat) {
if (seat.order == editPanel._order) {
Ext.Msg.show({
message: Ext.String.format(Ngcp.csc.locales.pbxconfig.devices.delete_assignment[localStorage.getItem('languageSelected')], seat.order),
buttons: Ext.Msg.YESNO,
icon: Ext.Msg.QUESTION,
fn: function(btn) {
if (btn === 'yes') {
seat.name = null;
seat.type = null;
me.commitUnsavedChanges();
me.fireEvent('showmessage', true, Ngcp.csc.locales.pbxconfig.changes_saved[localStorage.getItem('languageSelected')])
showPanel.hide();
}
}
});
return;
}
});
},
saveSeat: function() {
var me = this;
var grid = this.lookupReference('devicesGrid');
var selectedRec = this.getSelectedRec();
var showPanel = Ext.ComponentQuery.query('#seat-show-panel-' + selectedRec.get('id'))[0];
var editPanel = Ext.ComponentQuery.query('#seat-edit-panel-' + selectedRec.get('id'))[0];
var type = editPanel.down('[name=typeValue]').getValue();
var user = editPanel.down('[name=seat]').getValue();
Ext.each(selectedRec.get('seats'), function(seat) {
if (seat.order == editPanel._order) {
// workaround; TODO improve with binding in next iterations
seat.name = user;
seat.type = type;
editPanel._user = user;
editPanel._type = type;
showPanel.down('[name=typeValue]').setHtml(type + ": " + user);
me.fireEvent('showmessage', true, Ngcp.csc.locales.pbxconfig.changes_saved[localStorage.getItem('languageSelected')])
return;
}
});
me.commitUnsavedChanges();
showPanel.show();
editPanel.hide();
},
commitUnsavedChanges: function() {
var grid = this.lookupReference('devicesGrid');
var selectedRec = this.getSelectedRec();
var showPanel = Ext.ComponentQuery.query('#seat-show-panel-' + selectedRec.get('id'))[0];
selectedRec.set('imageWithButtons', null, {silent: true});
grid.getStore().commitChanges();
this.keepRowExpanded(grid, selectedRec);
Ext.Function.defer(function() {
grid.getView().refresh();
}, 50);
},
discardChanges: function() {
var showPanel = Ext.ComponentQuery.query('#seat-show-panel-' + this.getSelectedRec().get('id'))[0];
var editPanel = Ext.ComponentQuery.query('#seat-edit-panel-' + this.getSelectedRec().get('id'))[0];
showPanel.show();
editPanel.hide();
},
getSelectedRec: function() {
var grid = this.lookupReference('devicesGrid');
var selectedRec = grid.getSelectionModel().getSelection()[0];
return selectedRec;
}
});

@ -6,16 +6,25 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.devices.DevicesGrid', {
reference: 'devicesGrid',
store: 'Devices',
viewModel: 'devices',
viewConfig: {
stripeRows: false,
enableTextSelection: true
enableTextSelection: true,
preserveScrollOnRefresh: true,
preserveScrollOnReload: true
},
listeners: {
click: {
fn: 'onIconClicked',
element: 'el',
delegate: 'div.card-icon'
delegate: '.card-icon'
},
mouseenter: {
fn: 'onMouseEntered',
element: 'el',
delegate: '.card-icon'
},
cellclick: 'expandRow',
rowbodyclick: 'expandRow'
@ -38,7 +47,9 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.devices.DevicesGrid', {
plugins: [{
pluginId: 'rowwidgetDevices',
ptype: 'rowwidget',
selectRowOnExpand: true,
widget: {
cls: 'devices',
xtype: 'form',
defaultBindProperty: 'hidden',
bind: {
@ -49,142 +60,289 @@ Ext.define('NgcpCsc.view.pages.pbxconfig.devices.DevicesGrid', {
layout: 'hbox'
},
items: [{
name: 'name',
defaults: {
padding: '0 0 15 0'
},
items: [{
xtype: 'label',
bind: {
id: 'devices-label-mainname-{record.id}'
name: 'name',
defaults: {
padding: '0 0 15 0'
},
hidden: true,
cls: 'pbx-data-value',
text: Ngcp.csc.locales.pbxconfig.name[localStorage.getItem('languageSelected')],
width: 120
items: [{
xtype: 'label',
bind: {
id: 'devices-label-mainname-{record.id}'
},
hidden: true,
cls: 'pbx-data-value',
text: Ngcp.csc.locales.pbxconfig.station_name[localStorage.getItem('languageSelected')],
width: 120
}, {
xtype: 'textfield',
required: true,
hidden: true,
emptyText: Ngcp.csc.locales.pbxconfig.enter_new_name[localStorage.getItem('languageSelected')],
bind: {
id: 'devices-textfield-name-{record.id}'
},
listeners: {
// Workaround. Issue when binding is used, any change in any record field triggers a
// layout break in the row which looks like row collapse, but is not
focus: {
fn: 'setFieldValue'
},
specialkey: 'onEnterPressed'
}
}]
}, {
xtype: 'textfield',
required: true,
hidden: true,
emptyText: Ngcp.csc.locales.pbxconfig.enter_new_name[localStorage.getItem('languageSelected')],
bind: {
id: 'devices-textfield-name-{record.id}'
name: 'mac',
defaults: {
padding: '0 0 15 0'
},
listeners: {
// Workaround. Issue when binding is used, any change in any record field triggers a
// layout break in the row which looks like row collapse, but is not
focus: {
fn: 'setFieldValue'
items: [{
xtype: 'label',
cls: 'pbx-data-value',
text: Ngcp.csc.locales.pbxconfig.mac[localStorage.getItem('languageSelected')],
width: 120
}, {
xtype: 'label',
hidden: false,
bind: {
id: 'devices-label-mac-{record.id}',
text: '{record.mac}'
}
}, {
xtype: 'textfield',
required: true,
hidden: true,
emptyText: Ngcp.csc.locales.pbxconfig.enter_new_mac_address[localStorage.getItem('languageSelected')],
bind: {
id: 'devices-textfield-mac-{record.id}'
},
specialkey: 'onEnterPressed'
}
}]
}, {
name: 'device',
defaults: {
padding: '0 0 15 0'
},
items: [{
xtype: 'label',
cls: 'pbx-data-value',
text: Ngcp.csc.locales.pbxconfig.device[localStorage.getItem('languageSelected')],
width: 120
}, {
xtype: 'label',
hidden: false,
bind: {
id: 'devices-label-device-{record.id}',
text: '{record.device}'
}
listeners: {
focus: {
fn: 'setFieldValue'
},
specialkey: 'onEnterPressed'
}
}]
}, {
xtype: 'textfield',
required: true,
hidden: true,
emptyText: Ngcp.csc.locales.pbxconfig.enter_new_device[localStorage.getItem('languageSelected')],
bind: {
id: 'devices-textfield-device-{record.id}'
name: 'device',
defaults: {
padding: '0 0 15 0'
},
listeners: {
focus: {
fn: 'setFieldValue'
items: [{
xtype: 'label',
cls: 'pbx-data-value',
text: Ngcp.csc.locales.pbxconfig.device[localStorage.getItem('languageSelected')],
width: 120
}, {
xtype: 'label',
hidden: false,
bind: {
id: 'devices-label-device-{record.id}',
text: '{record.device}'
}
}, {
xtype: 'combo',
required: true,
autoSelect: false,
hidden: true,
emptyText: Ngcp.csc.locales.pbxconfig.enter_new_device[localStorage.getItem('languageSelected')],
bind: {
id: 'devices-textfield-device-{record.id}'
},
specialkey: 'onEnterPressed'
}
}]
}, {
name: 'mac',
defaults: {
padding: '0 0 15 0'
},
items: [{
xtype: 'label',
cls: 'pbx-data-value',
text: Ngcp.csc.locales.pbxconfig.mac[localStorage.getItem('languageSelected')],
width: 120
listeners: {
focus: 'setFieldValue',
specialkey: 'onEnterPressed',
select: 'deviceSelected'
},
store: ['Cisco Pbx 1', 'Cisco Pbx 2', 'Cisco Pbx 3']
}]
}, {
xtype: 'label',
hidden: false,
bind: {
id: 'devices-label-mac-{record.id}',
text: '{record.mac}'
}
name: 'extension',
defaults: {
padding: '0 0 15 0'
},
items: [{
xtype: 'label',
cls: 'pbx-data-value',
text: Ngcp.csc.locales.pbxconfig.extension[localStorage.getItem('languageSelected')] + " 1:",
width: 120
}, {
xtype: 'label',
hidden: false,
bind: {
id: 'devices-label-extension-{record.id}',
text: '{record.extension}'
}
}, {
xtype: 'combo',
required: true,
editable: false,
_skipSaveValidation: true,
hidden: true,
emptyText: Ngcp.csc.locales.pbxconfig.enter_new_extension[localStorage.getItem('languageSelected')],
bind: {
id: 'devices-textfield-extension-{record.id}'
},
listeners: {
focus: {
fn: 'setFieldValue'
},
specialkey: 'onEnterPressed'
},
store: ['Ext1', 'Ext2', 'Ext3']
}]
}, {
xtype: 'textfield',
required: true,
hidden: true,
emptyText: Ngcp.csc.locales.pbxconfig.enter_new_mac_address[localStorage.getItem('languageSelected')],
bind: {
id: 'devices-textfield-mac-{record.id}'
name: 'extension2',
editable: false,
defaults: {
padding: '0 0 15 0'
},
listeners: {
focus: {
fn: 'setFieldValue'
items: [{
xtype: 'label',
cls: 'pbx-data-value',
text: Ngcp.csc.locales.pbxconfig.extension[localStorage.getItem('languageSelected')] + " 2:",
width: 120
}, {
xtype: 'label',
hidden: false,
bind: {
id: 'devices-label-extension2-{record.id}',
text: '{record.extension2}'
}
}, {
xtype: 'combo',
_skipSaveValidation: true,
required: true,
hidden: true,
emptyText: Ngcp.csc.locales.pbxconfig.enter_new_extension[localStorage.getItem('languageSelected')],
bind: {
id: 'devices-textfield-extension2-{record.id}'
},
specialkey: 'onEnterPressed'
}
}]
}, {
name: 'status',
defaults: {
padding: '0 0 15 0'
listeners: {
focus: {
fn: 'setFieldValue'
},
specialkey: 'onEnterPressed'
},
store: ['Ext1', 'Ext2', 'Ext3']
}]
},
items: [{
xtype: 'label',
cls: 'pbx-data-value',
text: Ngcp.csc.locales.pbxconfig.status[localStorage.getItem('languageSelected')],
width: 120
{
xtype: 'panel',
layout: {
type: 'hbox'
},
defaults: {
margin: 20
},
items: [{
cls: 'device-img',
xtype: 'label',
width: 500,
height: 500,
bind: {
html: '{record.imageWithButtons}',
hidden: '{!record.image}'
}
}, {
xtype: 'fieldset',
width: 200,
margin: '200 0 0 0',
collapsible: false,
hidden: true,
defaults: {
xtype: 'label',
labelWidth: 50,
anchor: '100%',
},
bind: {
id: 'seat-show-panel-{record.id}'
},
items: [{
name: 'typeValue'
}, {
xtype: 'buttongroup',
name: 'editBtns',
columns: 3,
hidden: true,
cls: 'edit-panel',
border: 0,
defaults: {
width: 75
},
items: [{
iconCls: Ngcp.csc.icons.edit,
handler: 'editSeat',
tooltip: Ngcp.csc.locales.common.edit[localStorage.getItem('languageSelected')]
}, {
iconCls: Ngcp.csc.icons.trash,
handler: 'deleteSeat',
name: 'deleteBtn',
tooltip: Ngcp.csc.locales.common.delete[localStorage.getItem('languageSelected')]
}]
}]
}, {
xtype: 'fieldset',
margin: '200 0 0 0',
cls: 'devices-seat-fieldset',
width: 200,
collapsible: false,
hidden: true,
defaults: {
labelWidth: 40,
anchor: '100%',
},
bind: {
id: 'seat-edit-panel-{record.id}'
},
items: [{
xtype: 'combo',
editable: false,
name: 'typeValue',
_skipSaveValidation: true,
fieldLabel: 'Type',
store: ['Shared', 'Speed dial', 'Busy lamp', 'Private'],
allowBlank: false
}, {
xtype: 'combo',
editable: false,
_skipSaveValidation: true,
store: ['User1', 'User2', 'User3', 'User4'],
name: 'seat',
fieldLabel: 'User',
allowBlank: false
}, {
xtype: 'buttongroup',
name: 'editBtns',
columns: 3,
cls: 'edit-panel',
border: 0,
defaults: {
width: 75
},
items: [{
iconCls: Ngcp.csc.icons.floppy,
handler: 'saveSeat',
tooltip: Ngcp.csc.locales.common.save[localStorage.getItem('languageSelected')]
}, {
iconCls: Ngcp.csc.icons.block,
handler: 'discardChanges',
tooltip: Ngcp.csc.locales.common.reset[localStorage.getItem('languageSelected')]
}]
}]
}]
}, {
xtype: 'label',
hidden: false,
bind: {
id: 'devices-label-status-{record.id}',
text: '{record.status}'
}
}, {
xtype: 'textfield',
required: true,
hidden: true,
emptyText: Ngcp.csc.locales.pbxconfig.enter_new_status[localStorage.getItem('languageSelected')],
bind: {
id: 'devices-textfield-status-{record.id}'
},
listeners: {
focus: {
fn: 'setFieldValue'
},
specialkey: 'onEnterPressed'
html: '<div class="card-wrapper"><div class="card-icon-row">' +
'<div id="removeDevice-{record.id}" class="card-icon" data-callback="removeCard" data-qtip="' + Ngcp.csc.locales.filters.tooltips.remove_seat[localStorage.getItem('languageSelected')] + '"><i class="' + Ngcp.csc.icons.trash2x + ' green-icon pointer" aria-hidden="true"></i></div>' +
'<div id="editDevice-{record.id}" class="card-icon" data-callback="editCard" data-qtip="' + Ngcp.csc.locales.filters.tooltips.edit_seat[localStorage.getItem('languageSelected')] + '"><i class="' + Ngcp.csc.icons.edit2x + ' green-icon pointer" aria-hidden="true"></i></div>' +
'<div id="cancelDevice-{record.id}" class="card-icon hidden" data-callback="cancelCard" data-qtip="' + Ngcp.csc.locales.pbxconfig.cancel_operation[localStorage.getItem('languageSelected')] + '"><i class="' + Ngcp.csc.icons.block2x + ' green-icon pointer" aria-hidden="true"></i></div>' +
'</div></div>'
}
}]
}, {
xtype: 'label',
bind: {
html: '<div class="card-wrapper"><div class="card-icon-row">' +
'<div id="removeDevice-{record.id}" class="card-icon" data-callback="removeCard" data-qtip="' + Ngcp.csc.locales.filters.tooltips.remove_seat[localStorage.getItem('languageSelected')] + '"><i class="' + Ngcp.csc.icons.trash2x + ' green-icon pointer" aria-hidden="true"></i></div>' +
'<div id="editDevice-{record.id}" class="card-icon" data-callback="editCard" data-qtip="' + Ngcp.csc.locales.filters.tooltips.edit_seat[localStorage.getItem('languageSelected')] + '"><i class="' + Ngcp.csc.icons.edit2x + ' green-icon pointer" aria-hidden="true"></i></div>' +
'<div id="cancelDevice-{record.id}" class="card-icon hidden" data-callback="cancelCard" data-qtip="' + Ngcp.csc.locales.pbxconfig.cancel_operation[localStorage.getItem('languageSelected')] + '"><i class="' + Ngcp.csc.icons.block2x + ' green-icon pointer" aria-hidden="true"></i></div>' +
'</div></div>'
}
}]
]
}
}]
});

@ -1,39 +0,0 @@
Ext.define('NgcpCsc.view.pages.devices.DestinationsGrid', {
extend: 'Ext.grid.Panel',
xtype: 'destinations-grid',
reference: 'destinationsGrid',
store: 'Destinations',
rowLines: false,
viewConfig: {
stripeRows: false,
columnLines: false
},
plugins: {
ptype: 'cellediting',
clicksToEdit: 1
},
columns: {
defaults: {
menuDisabled: true,
resizable: false
},
items: [{
flex: 1,
dataIndex: 'position',
text: '#'
},{
flex: 5,
dataIndex: 'destination',
editor: 'textfield',
text: Ngcp.csc.locales.pbxconfig.destination[localStorage.getItem('languageSelected')]
}]
}
})

@ -1,146 +1,189 @@
{
"data": [{
"id": 1,
"name":"Device1",
"name": "Device1",
"device": "Cisco Pbx 1",
"mac":"00-14-22-01-23-41",
"status": "disabled",
"image": "/resources/images/pbx.png",
"destinations": [{
"name": "destination1",
"sound": "resources/audio/voicemail.mp3",
"mac": "00-14-22-01-23-41",
"extension": "Ext2",
"extension2": "Ext1",
"image": "/resources/images/cisco1.jpg",
"seats": [{
"name": "User1 (130)",
"type": "Shared",
"order": 1,
"position": {
"top": "14%",
"left": "45%"
"top": "12%",
"left": "52%",
"anchor": "right"
}
}, {
"name": "destination2",
"sound": "resources/audio/voicemail.mp3",
"order": 2,
"position": {
"top": "18%",
"left": "45%"
"top": "16%",
"left": "52%",
"anchor": "right"
}
}, {
"name": "destination3",
"sound": "resources/audio/voicemail.mp3",
"name": "User3",
"order": 3,
"type": "Speed dial",
"position": {
"top": "22%",
"left": "45%"
"top": "19%",
"left": "52%",
"anchor": "right"
}
}, {
"name": "destination4",
"sound": "resources/audio/voicemail.mp3",
"name": "User4",
"order": 4,
"type": "Shared",
"position": {
"top": "41%",
"left": "54%"
"top": "30%",
"left": "60%",
"anchor": "top"
}
}, {
"name": "destination5",
"sound": "resources/audio/voicemail.mp3",
"name": "User5",
"order": 5,
"type": "Speed dial",
"position": {
"top": "41%",
"left": "61%"
"top": "30%",
"left": "67%",
"anchor": "top"
}
}, {
"name": "destination6",
"sound": "resources/audio/voicemail.mp3",
"name": "User6",
"order": 6,
"type": "Busy lamp",
"position": {
"top": "41%",
"left": "67%"
"top": "30%",
"left": "74%",
"anchor": "top"
}
}]
}, {
"id": 2,
"name":"Device2",
"name": "Device2",
"device": "Cisco Pbx 2",
"mac":"00-14-22-01-23-42",
"status": "enabled",
"mac": "00-14-22-01-23-42",
"extension": "Ext2",
"extension2": "Ext1",
"image": "/resources/images/cisco2.jpg",
"destinations": [{
"name": "destination1",
"sound": "resources/audio/voicemail.mp3",
"seats": [{
"name": "User1",
"order": 1,
"type": "Busy lamp",
"position": {
"top": "13%",
"left": "86%"
"top": "15%",
"left": "90%",
"anchor": "left"
}
}, {
"name": "destination2",
"sound": "resources/audio/voicemail.mp3",
"name": "User2",
"order": 2,
"type": "Speed dial",
"position": {
"top": "17%",
"left": "86%"
"top": "18%",
"left": "90%",
"anchor": "left"
}
}, {
"name": "destination3",
"sound": "resources/audio/voicemail.mp3",
"name": "User3",
"order": 3,
"type": "Shared",
"position": {
"top": "21%",
"left": "86%"
"top": "22%",
"left": "90%",
"anchor": "left"
}
}]
}, {
"id": 3,
"name":"Device3",
"name": "Device3",
"device": "Cisco Pbx 3",
"mac":"00-14-22-01-23-43",
"status": "enabled",
"mac": "00-14-22-01-23-43",
"extension": "Ext2",
"extension2": "Ext1",
"image": "/resources/images/cisco3.jpg",
"destinations": [{
"name": "destination1",
"sound": "resources/audio/voicemail.mp3",
"seats": [{
"name": "User1",
"order": 1,
"type": "Busy lamp",
"position": {
"top": "34%",
"left": "56%"
"top": "35%",
"left": "59%",
"anchor": "top"
}
}, {
"name": "destination2",
"sound": "resources/audio/voicemail.mp3",
"name": "User2",
"order": 2,
"type": "Shared",
"position": {
"top": "34%",
"left": "83%"
"top": "35%",
"left": "81%",
"anchor": "top"
}
}]
}, {
"id": 4,
"name":"Device4",
"device": "Cisco Pbx 4",
"mac":"00-14-22-01-23-44",
"status": "enabled",
"name": "Device4",
"device": "Cisco Pbx 1",
"mac": "00-14-22-01-23-44",
"extension": "Ext2",
"extension2": "Ext1",
"image": "/resources/images/cisco1.jpg",
"destinations": [{
"name": "destination1",
"sound": "resources/audio/voicemail.mp3",
"seats": [{
"name": "User1",
"type": "Shared",
"order": 1,
"position": {
"top": "11%",
"left": "49%"
"top": "12%",
"left": "52%",
"anchor": "right"
}
}, {
"name": "destination2",
"sound": "resources/audio/voicemail.mp3",
"name": "User2",
"order": 2,
"type": "Busy lamp",
"position": {
"top": "22%",
"left": "49%"
"top": "16%",
"left": "52%",
"anchor": "right"
}
}, {
"name": "destination3",
"sound": "resources/audio/voicemail.mp3",
"name": "User3",
"order": 3,
"type": "Speed dial",
"position": {
"top": "19%",
"left": "52%",
"anchor": "right"
}
}, {
"name": "User4",
"order": 4,
"type": "Shared",
"position": {
"top": "30%",
"left": "60%",
"anchor": "top"
}
}, {
"name": "User5",
"order": 5,
"type": "Speed dial",
"position": {
"top": "30%",
"left": "67%",
"anchor": "top"
}
}, {
"name": "User6",
"order": 6,
"type": "Busy lamp",
"position": {
"top": "38%",
"left": "67%"
"top": "30%",
"left": "74%",
"anchor": "top"
}
}]
}]

@ -2,133 +2,115 @@
"data": [{
"id": 1,
"name": "Cisco Pbx 1",
"image": "/resources/images/pbx.png",
"destinations": [{
"name": "destination1",
"sound": "resources/audio/voicemail.mp3",
"image": "/resources/images/cisco1.jpg",
"seats": [{
"name": "User1",
"type": "Shared",
"order": 1,
"position": {
"top": "14%",
"left": "45%"
"top": "12%",
"left": "52%",
"anchor": "right"
}
}, {
"name": "destination2",
"sound": "resources/audio/voicemail.mp3",
"name": "User2",
"order": 2,
"type": "Busy lamp",
"position": {
"top": "18%",
"left": "45%"
"top": "16%",
"left": "52%",
"anchor": "right"
}
}, {
"name": "destination3",
"sound": "resources/audio/voicemail.mp3",
"name": "User3",
"order": 3,
"type": "Speed dial",
"position": {
"top": "22%",
"left": "45%"
"top": "19%",
"left": "52%",
"anchor": "right"
}
}, {
"name": "destination4",
"sound": "resources/audio/voicemail.mp3",
"name": "User4",
"order": 4,
"type": "Shared",
"position": {
"top": "41%",
"left": "54%"
"top": "30%",
"left": "60%",
"anchor": "top"
}
}, {
"name": "destination5",
"sound": "resources/audio/voicemail.mp3",
"name": "User5",
"order": 5,
"type": "Speed dial",
"position": {
"top": "41%",
"left": "61%"
"top": "30%",
"left": "67%",
"anchor": "top"
}
}, {
"name": "destination6",
"sound": "resources/audio/voicemail.mp3",
"name": "User6",
"order": 6,
"type": "Busy lamp",
"position": {
"top": "41%",
"left": "67%"
"top": "30%",
"left": "74%",
"anchor": "top"
}
}]
}, {
"id": 2,
"name": "Cisco Pbx 2",
"image": "/resources/images/cisco2.jpg",
"destinations": [{
"name": "destination1",
"sound": "resources/audio/voicemail.mp3",
"seats": [{
"name": "User1",
"order": 1,
"type": "Busy lamp",
"position": {
"top": "13%",
"left": "86%"
"top": "15%",
"left": "90%",
"anchor": "left"
}
}, {
"name": "destination2",
"sound": "resources/audio/voicemail.mp3",
"name": "User2",
"order": 2,
"type": "Speed dial",
"position": {
"top": "17%",
"left": "86%"
"top": "18%",
"left": "90%",
"anchor": "left"
}
}, {
"name": "destination3",
"sound": "resources/audio/voicemail.mp3",
"name": "User3",
"order": 3,
"type": "Shared",
"position": {
"top": "21%",
"left": "86%"
"top": "22%",
"left": "90%",
"anchor": "left"
}
}]
}, {
"id": 3,
"name": "Cisco Pbx 3",
"image": "/resources/images/cisco3.jpg",
"destinations": [{
"name": "destination1",
"sound": "resources/audio/voicemail.mp3",
"order": 1,
"position": {
"top": "34%",
"left": "56%"
}
}, {
"name": "destination2",
"sound": "resources/audio/voicemail.mp3",
"order": 2,
"position": {
"top": "34%",
"left": "83%"
}
}]
}, {
"id": 4,
"name": "Cisco Pbx 4",
"image": "/resources/images/cisco1.jpg",
"destinations": [{
"name": "destination1",
"sound": "resources/audio/voicemail.mp3",
"seats": [{
"name": "User1",
"order": 1,
"type": "Busy lamp",
"position": {
"top": "11%",
"left": "49%"
"top": "35%",
"left": "59%",
"anchor": "top"
}
}, {
"name": "destination2",
"sound": "resources/audio/voicemail.mp3",
"name": "User2",
"order": 2,
"type": "Shared",
"position": {
"top": "22%",
"left": "49%"
}
}, {
"name": "destination3",
"sound": "resources/audio/voicemail.mp3",
"order": 3,
"position": {
"top": "38%",
"left": "67%"
"top": "35%",
"left": "81%",
"anchor": "top"
}
}]
}]

Loading…
Cancel
Save