Browse Source

UI-1220: Added the VMBox category + Main VMBox auto-creation

4.3
Jean-Roch Maitre 11 years ago
parent
commit
2c6314fd42
14 changed files with 1125 additions and 69 deletions
  1. +12
    -39
      app.js
  2. +94
    -2
      i18n/en-US.json
  3. +8
    -2
      i18n/fr-FR.json
  4. +1
    -0
      style/app.css
  5. +63
    -0
      submodules/myOffice/myOffice.js
  6. +2
    -2
      submodules/numbers/numbers.js
  7. +0
    -1
      submodules/users/users.js
  8. +241
    -0
      submodules/vmboxes/vmboxes.css
  9. +432
    -0
      submodules/vmboxes/vmboxes.js
  10. +32
    -23
      views/app.html
  11. +182
    -0
      views/vmboxes-edit.html
  12. +4
    -0
      views/vmboxes-emailRow.html
  13. +35
    -0
      views/vmboxes-layout.html
  14. +19
    -0
      views/vmboxes-row.html

+ 12
- 39
app.js View File

@ -17,7 +17,7 @@ define(function(require){
requests: {},
subscribe: {},
subModules: ['devices', 'groups', 'numbers', 'strategy', 'callLogs', 'users', 'myOffice', 'featureCodes'],
subModules: ['devices', 'groups', 'numbers', 'strategy', 'callLogs', 'users', 'myOffice', 'featureCodes', 'vmboxes'],
load: function(callback){
var self = this;
@ -61,49 +61,22 @@ define(function(require){
container = parent.find('.right-content');
parent.find('.category').on('click', function() {
// Get the ID of the submodule to render
var $this = $(this),
args = {
parent: container
},
id = $this.attr('id');
// Display the category we clicked as active
parent
.find('.category')
.removeClass('active');
$this.toggleClass('active');
// Empty the main container and then render the submodule content
container.empty();
$(this).toggleClass('active');
});
var args = {
parent: container
};
parent.find('.category#my_office').on('click', function() {
monster.pub('voip.myOffice.render', args);
});
parent.find('.category#users').on('click', function() {
monster.pub('voip.users.render', args);
});
parent.find('.category#groups').on('click', function() {
monster.pub('voip.groups.render', args);
});
parent.find('.category#numbers').on('click', function() {
monster.pub('voip.numbers.render', container);
});
parent.find('.category#devices').on('click', function() {
monster.pub('voip.devices.render', args);
});
parent.find('.category#strategy').on('click', function() {
monster.pub('voip.strategy.render', args);
});
parent.find('.category#call_logs').on('click', function() {
monster.pub('voip.callLogs.render', args);
});
parent.find('.category#feature_codes').on('click', function() {
monster.pub('voip.featureCodes.render', args);
monster.pub('voip.' + id + '.render', args);
});
}
};


+ 94
- 2
i18n/en-US.json View File

@ -12,7 +12,10 @@
"mainNumber": "Main Number",
"callLogs": "Call Logs",
"quickLinks": "Help Topics",
"featureCodes": "Feature Codes"
"featureCodes": "Feature Codes",
"__comment": "UI-1220: Added VMBox module",
"__version": "3.19",
"vmboxes": "Voicemail Boxes"
},
"groups": {
@ -750,7 +753,10 @@
"tollfree": "Toll-free Numbers",
"international": "International Numbers",
"noNumber": "No number available"
}
},
"__comment": "UI-1220: Adding a Main VMBox automatically when they first load the SmartPBX if they don't have one",
"__version": "3.19",
"mainVMBoxName": "Main Voicemail Box"
},
"__comment": "UI-299, v3.19_s2: Added the Feature Codes tab to SmartPBX.",
@ -795,5 +801,91 @@
"do_not_disturb": "Do Not Disturb",
"misc": "Miscellaneous"
}
},
"__comment": "UI-1220: Added VMBox module",
"__version": "3.19",
"vmboxes": {
"addTitle": "Adding a Voicemail Box",
"editTitle": "Editing a Voicemail Box: {{ name }}",
"title": "Total Voicemail Boxes",
"add": "Add Voicemail Box",
"new": "New Voicemail Box",
"createVmbox": "Create new Voicemail Box",
"deleteVmbox": "Delete Voicemail Box",
"deleteNotAllowed": "You can not delete this Voicemail Box because it belongs to a User",
"confirmDeleteVmbox": "This Voicemail Box will be permanently deleted. Continue?",
"deletedVmbox": "You successfully deleted the following Voicemail Box \"{{vmboxName}}\".",
"titleGrid": {
"name": "Name",
"number": "Number",
"owner": "User",
"edit": "Edit"
},
"noMatchingVMBoxes": "There were no Voicemail Boxes found matching your search",
"noVMBoxesConfigured": "There are no Voicemail Boxes configured",
"popupSettings": {
"advancedTitle": "Advanced",
"basicTitle": "Basic Settings",
"basicSectionTitle": "Basic Settings",
"basic": {
"name": {
"label": "Name"
},
"number": {
"label": "Voicemail Number"
},
"pinNumber": {
"label": "PIN Number"
}
},
"options": {
"menuTitle": "Options",
"sectionTitle": "Options",
"timezone": {
"label": "Timezone"
},
"unavailableMessage": {
"label": "Unavailable Message"
},
"timezone": {
"label": "Timezone"
},
"alreadySetup": {
"label": "Already Setup?",
"help": "Is this voicemail box already considered initialized? If not, the first time the user logs in they will be forced to change their PIN and setup a greeting."
},
"requirePIN": {
"label": "Require PIN?",
"help": "Check if voicemail requires a PIN."
},
"autoLogin": {
"label": "Auto-Login Enabled?",
"help": "Check to enable auto-login for this voicemail box? (If the user call his own voicemail, it goes straight to his messages)"
},
"skipGreetings": {
"label": "Skip Greetings?",
"help": "Check to skip greetings by default"
},
"skipInstructions": {
"label": "Skip Instructions?",
"help": "Check to skip instructions by default"
},
"deleteAfterNotify": {
"label": "Delete after Notification?",
"help": "Delete the voicemail after the notification has been sent"
},
"configurable": {
"label": "Configurable via Menu?",
"help": " If unchecked, it will disallow the user to configure voicemail via the menu"
}
},
"recipients": {
"menuTitle": "Recipients",
"sectionTitle": "Recipients",
"header": "This panel lets you manage who will be notified when someones leave a message on this voicemail box. Click on \"Add New Recipient\" to add an e-mail address to the list",
"create": "Add New Recipient"
}
}
}
}

+ 8
- 2
i18n/fr-FR.json View File

@ -11,7 +11,10 @@
"devices": "Téléphones",
"mainNumber": "Numéro principal",
"callLogs": "Journal d'appels",
"quickLinks": "Aide"
"quickLinks": "Aide",
"__comment": "UI-1220: Added VMBox module",
"__version": "3.19",
"vmboxes": "Répondeurs"
},
"groups": {
@ -726,7 +729,10 @@
"tollfree": "Numéros verts",
"international": "Numéros internationaux",
"noNumber": "Aucun numéro disponible"
}
},
"__comment": "UI-1220: Adding a Main VMBox automatically when they first load the SmartPBX if they don't have one",
"__version": "3.19",
"mainVMBoxName": "Répondeur Principal"
},
"__comment": "UI-299, v3.19_s2: Added the Feature Codes tab to SmartPBX.",


+ 1
- 0
style/app.css View File

@ -6,6 +6,7 @@
@import url('../submodules/callLogs/callLogs.css');
@import url('../submodules/users/users.css');
@import url('../submodules/featureCodes/featureCodes.css');
@import url('../submodules/vmboxes/vmboxes.css');
#voip_container .left-menu #my_office {
margin-bottom: 20px;


+ 63
- 0
submodules/myOffice/myOffice.js View File

@ -113,6 +113,64 @@ define(function(require){
});
},
myOfficeCreateMainVMBoxIfMissing: function(callback) {
var self = this;
self.myOfficeHasMainVMBox(
function(vmbox) {
callback(vmbox);
},
function() {
self.myOfficeCreateMainVMBox(function(vmbox) {
callback(vmbox);
})
}
);
},
myOfficeCreateMainVMBox: function(callback) {
var self = this,
vmboxData = {
mailbox: '0',
type: 'mainVMBox',
name: self.i18n.active().myOffice.mainVMBoxName,
delete_after_notify: true
};
self.callApi({
resource: 'voicemail.create',
data: {
accountId: self.accountId,
data: vmboxData
},
success: function(vmbox) {
callback && callback(vmbox.data);
}
});
},
myOfficeHasMainVMBox: function(hasVMBoxCallback, noVMBoxCallback) {
var self = this;
self.callApi({
resource: 'voicemail.list',
data: {
accountId: self.accountId,
filters: {
'filter_type':'mainVMBox'
}
},
success: function(vmboxes) {
if(vmboxes.data.length > 0) {
hasVMBoxCallback && hasVMBoxCallback(vmboxes[0]);
}
else {
noVMBoxCallback && noVMBoxCallback();
}
}
});
},
myOfficeLoadData: function(callback) {
var self = this;
@ -128,6 +186,11 @@ define(function(require){
}
});
},
mainVoicemailBox: function(parallelCallback) {
self.myOfficeCreateMainVMBoxIfMissing(function(vmbox) {
parallelCallback(null, vmbox);
});
},
users: function(parallelCallback) {
self.callApi({
resource: 'user.list',


+ 2
- 2
submodules/numbers/numbers.js View File

@ -11,9 +11,9 @@ define(function(require){
'voip.numbers.render': 'numbersRender'
},
numbersRender: function(container){
numbersRender: function(args){
var self = this,
parent = container || $('#ws_content');
parent = args.parent || $('#ws_content');
monster.pub('common.numbers.render', {
container: parent,


+ 0
- 1
submodules/users/users.js View File

@ -481,7 +481,6 @@ define(function(require){
var originalData = self.usersFormatAddUser(results),
userTemplate = $(monster.template(self, 'users-creation', originalData));
timezone.populateDropdown(userTemplate.find('#user_creation_timezone'));
monster.ui.prettyCheck.create(userTemplate);
monster.ui.validate(userTemplate.find('#form_user_creation'), {


+ 241
- 0
submodules/vmboxes/vmboxes.css View File

@ -0,0 +1,241 @@
#vmboxes_container .vmboxes-header {
font-size: 18px;
line-height: 30px;
}
#vmboxes_container .vmboxes-header > * {
display: inline-block;
}
#vmboxes_container .vmboxes-header .title {
padding: 15px;
border: 1px solid #dcdcdc;
border-radius: 4px 0 0 4px;
}
#vmboxes_container .vmboxes-header .count-vmboxes {
display: inline-block;
margin-top: -5px;
margin-left: 15px;
color: #22ccff;
font-weight: 600;
font-size: 28px;
}
#vmboxes_container .vmboxes-header .dropdown {
vertical-align: bottom;
}
#vmboxes_container .vmboxes-header .add-vmbox {
margin: 0;
padding: 9px 13px;
border: 1px solid #dcdcdc;
border-left: 0;
border-radius: 0 4px 4px 0;
background-image: -webkit-linear-gradient(top, hsl(0, 0%, 98%) 0%, hsl(0, 0%, 95%) 100%);
background-image: -moz-linear-gradient(top, hsl(0, 0%, 98%) 0%, hsl(0, 0%, 95%) 100%);
background-image: -ms-linear-gradient(top, hsl(0, 0%, 98%) 0%, hsl(0, 0%, 95%) 100%);
background-image: -o-linear-gradient(top, hsl(0, 0%, 98%) 0%, hsl(0, 0%, 95%) 100%);
background-image: linear-gradient(top, hsl(0, 0%, 98%) 0%, hsl(0, 0%, 95%) 100%);
height: 42px;
vertical-align: top;
text-align: center;
font-size: 12px;
}
#vmboxes_container .vmboxes-header .add-vmbox:hover {
background-image: none;
background-color: #eee;
text-decoration: none;
}
#vmboxes_container .vmboxes-header .add-vmbox i {
display: block;
margin: 0;
color: #929799;
text-decoration: none;
}
#vmboxes_container .vmboxes-header .add-vmbox:hover i {
color: #22ccff;
}
#vmboxes_container .vmboxes-header .search-box { margin: 16px 0 16px 15px; }
#vmboxes_container .vmboxes-grid {
background: #fcfcfc;
border: 1px solid #ddd;
border-radius: 4px;
margin-top: 20px;
}
#vmboxes_container .vmboxes-grid i.icon-plus {
margin-left: 5px;
}
#vmboxes_container .vmboxes-grid .empty-search-row,
#vmboxes_container .vmboxes-grid .no-vmboxes-row {
display: none;
padding: 16px;
text-align: center;
}
#vmboxes_container .vmboxes-grid .grid-row.title:not(:last-child) {
border-bottom: 1px solid #ddd;
}
#vmboxes_container .vmboxes-grid .grid-row.title,
#vmboxes_container .vmboxes-grid .grid-row .user-cells{
height: 50px;
line-height: 50px; /* 60 - padding */
}
#vmboxes_container .vmboxes-grid .grid-row:not(:last-child) {
border-bottom: 1px solid #eee;
}
#vmboxes_container .vmboxes-grid .grid-row.title .grid-cell {
text-align: center;
padding-left: 0;
}
#vmboxes_container .vmboxes-grid .grid-row .grid-cell {
border-right: 1px solid #eee;
display: inline-block;
overflow: hidden;
padding-left: 10px;
width: 20%;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
#vmboxes_container .vmboxes-grid .grid-row .grid-cell:first-child {
border-left: none !important;
}
#vmboxes_container .vmboxes-grid .grid-row .grid-cell:last-child {
border-right: none !important;
}
#vmboxes_container .vmboxes-grid .grid-row .grid-cell:not(.features) {
white-space: nowrap;
}
#vmboxes_container .vmboxes-grid .grid-row .grid-cell.centered {
padding: 0;
text-align: center;
}
#vmboxes_container .vmboxes-grid .grid-row .grid-cell.right-aligned {
padding: 0 5px 0 0;
text-align: right;
}
#vmboxes_container .vmboxes-grid .grid-row .grid-cell.features a.dropdown-toggle {
padding: 15px 7px 2px 15px;
text-align: left;
background: transparent !important;
}
#vmboxes_container .vmboxes-cells {
height: 60px;
line-height: 60px;
}
/* Columns */
#vmboxes_container .vmboxes-grid .grid-row .grid-cell.number {
width: 20%;
}
#vmboxes_container .vmboxes-grid .grid-row .grid-cell.name {
width: 40%;
}
#vmboxes_container .vmboxes-grid .grid-row .grid-cell.owner {
width: 30%;
}
#vmboxes_container .vmboxes-grid .grid-row .grid-cell.edit {
width: 10%;
}
#vmboxes_container .vmboxes-grid .grid-row .grid-cell.edit .settings {
padding: 10px;
cursor: pointer;
}
#vmboxes_container .vmboxes-grid .grid-row .grid-cell.edit .settings:hover {
color: #000;
}
/* Adding / Edition vmboxes Popups */
.edit-vmbox {
width: 700px;
}
.edit-vmbox .actions {
border-top: 1px solid #CCCCCC;
height: 30px;
line-height: 30px;
padding: 15px;
}
.edit-vmbox .actions button {
margin-left: 5px;
}
.edit-vmbox .title-bar {
border-bottom: 1px solid #ccc;
margin-bottom: 20px;
padding: 15px 0;
}
.edit-vmbox .title-bar .vmbox-title > div {
display: inline-block;
float: left;
font-size: 18px;
font-weight: bold;
height: 80px;
line-height: 80px;
margin-left: 40px;
}
.edit-vmbox .title-bar .vmbox-title .vmbox-icon {
height: 75px;
line-height: 75px;
}
.edit-vmbox .title-bar .vmbox-title .vmbox-icon > i {
font-size: 48px;
vertical-align: middle;
}
.edit-vmbox .title-bar .nav-pills {
margin-top: 24px;
margin-right: 15px;
}
.edit-vmbox .content .tabs-section .title {
color: #22CCFF;
font-size: 24px;
margin-bottom: 30px;
margin-left: 40px;
text-shadow: 1px 0 1px #CCCCCC;
}
.edit-vmbox .control-input.checkbox {
margin-left: 160px;
}
.edit-vmbox .helper {
margin: 0 30px;
}
.edit-vmbox .helper i {
margin-right: 5px;
}
.edit-vmbox .list-entities.emails-list {
padding: 0 20px;
}

+ 432
- 0
submodules/vmboxes/vmboxes.js View File

@ -0,0 +1,432 @@
define(function(require){
var $ = require('jquery'),
_ = require('underscore'),
monster = require('monster'),
toastr = require('toastr'),
timezone = require('monster-timezone');
var app = {
requests: {},
subscribe: {
'voip.vmboxes.render': 'vmboxesRender'
},
/* Users */
/* args: parent and voicemailId */
vmboxesRender: function(args) {
var self = this,
args = args || {},
parent = args.parent || $('.right-content'),
_voicemailId = args.voicemailId || '';
self.vmboxesGetData(function(data) {
var dataTemplate = self.vmboxesFormatListData(data),
template = $(monster.template(self, 'vmboxes-layout', dataTemplate)),
templateVMBox;
_.each(dataTemplate.vmboxes, function(vmbox) {
templateVMBox = monster.template(self, 'vmboxes-row', vmbox);
template.find('.vmboxes-rows').append(templateVMBox);
});
self.vmboxesBindEvents(template, parent, dataTemplate);
parent
.empty()
.append(template);
if(_voicemailId) {
var row = parent.find('.grid-row[data-id=' + _voicemailId + ']');
monster.ui.highlight(row, {
endColor: '#FCFCFC'
});
}
if (dataTemplate.vmboxes.length == 0 ) {
parent.find('.no-vmboxes-row').css('display', 'block');
} else {
parent.find('.no-vmboxes-row').css('display', 'none');
}
});
},
vmboxesBindEvents: function(template, parent, data) {
var self = this,
callbackSave = function(vmbox) {
self.vmboxesRender({ voicemailId: vmbox.id });
};
template.find('.settings').on('click', function() {
self.vmboxesRenderEdit($(this).parents('.grid-row').data('id'), callbackSave);
});
template.find('.add-vmbox').on('click', function() {
self.vmboxesRenderEdit(undefined, callbackSave);
});
template.find('.vmboxes-header .search-query').on('keyup', function() {
var searchString = $(this).val().toLowerCase(),
rows = template.find('.vmboxes-rows .grid-row:not(.title)'),
emptySearch = template.find('.vmboxes-rows .empty-search-row');
_.each(rows, function(row) {
var row = $(row);
row.data('search').toLowerCase().indexOf(searchString) < 0 ? row.hide() : row.show();
});
if(rows.size() > 0) {
rows.is(':visible') ? emptySearch.hide() : emptySearch.show();
}
});
},
vmboxesRenderEdit: function(id, callback) {
var self = this;
self.vmboxesGetEditData(id, function(data) {
self.vmboxesRenderVmbox(data, callback);
});
},
vmboxesRenderVmbox: function(data, callback) {
var self = this
mode = data.id ? 'edit' : 'add',
popupTitle = mode === 'edit' ? monster.template(self, '!' + self.i18n.active().vmboxes.editTitle, { name: data.name }) : self.i18n.active().vmboxes.addTitle;
templateVMBox = $(monster.template(self, 'vmboxes-edit', data)),
callbacks = {
afterSave: function(vmbox) {
popup.dialog('close').remove();
callback && callback(vmbox);
},
afterDelete: function(vmbox) {
popup.dialog('close').remove();
self.vmboxesRender();
},
afterCancel: function() {
popup.dialog('close').remove();
}
};
_.each(data.notify_email_address, function(recipient) {
templateVMBox.find('.saved-entities')
.append(monster.template(self, 'vmboxes-emailRow', { name: recipient }));
});
self.vmboxesEditBindEvents(templateVMBox, data, callbacks);
var popup = monster.ui.dialog(templateVMBox, {
position: ['center', 20],
title: popupTitle
});
},
vmboxesEditBindEvents: function(templatVMBox, data, callbacks) {
var self = this,
vmboxForm = templateVMBox.find('#form_vmbox');
monster.ui.validate(vmboxForm, {
rules: {
'name': {
required: true
}
}
});
monster.ui.tabs(templateVMBox);
timezone.populateDropdown(templateVMBox.find('#timezone'), data.timezone);
templateVMBox.find('#timezone').chosen({search_contains: true, width: "40%"});
templateVMBox.find('[data-toggle="tooltip"]').tooltip();
templateVMBox.find('.switch').bootstrapSwitch();
templateVMBox.find('.actions .save').on('click', function() {
if(monster.ui.valid(vmboxForm)) {
var dataToSave = self.vmboxesMergeData(data, templateVMBox);
self.vmboxesSaveVmbox(dataToSave, function(data) {
callbacks.afterSave && callbacks.afterSave(data);
});
} else {
templateVMBox.find('.tabs-selector[data-section="basic"]').click();
}
});
templateVMBox.find('#delete_vmbox').on('click', function() {
var voicemailId = $(this).parents('.edit-vmbox').data('id');
monster.ui.confirm(self.i18n.active().vmboxes.confirmDeleteVmbox, function() {
self.vmboxesDeleteVmbox(voicemailId, function(vmbox) {
toastr.success(monster.template(self, '!' + self.i18n.active().vmboxes.deletedVmbox, { vmboxName: vmbox.name }));
callbacks.afterDelete && callbacks.afterDelete(vmbox);
});
});
});
templateVMBox.find('.actions .cancel-link').on('click', function() {
callbacks.afterCancel && callbacks.afterCancel();
});
// Recipients stuff
var addEntity = function(event) {
event.preventDefault();
var inputName = templateVMBox.find('#entity_name'),
name = inputName.val();
templateFlag = monster.template(self, 'vmboxes-emailRow', { name: name });
templateVMBox.find('.saved-entities').prepend(templateFlag);
inputName.val('')
.focus();
};
templateVMBox.find('.entity-wrapper.placeholder:not(.active)').on('click', function(){
$(this).addClass('active');
templateVMBox.find('#entity_name').focus();
});
templateVMBox.find('#cancel_entity').on('click', function(e) {
e.stopPropagation();
$(this).siblings('input').val('');
templateVMBox.find('.entity-wrapper.placeholder')
.removeClass('active');
});
templateVMBox.find('#add_entity').on('click', function(e) {
addEntity(e);
});
templateVMBox.find('#entity_name').on('keypress', function(e) {
var code = e.keyCode || e.which;
if(code === 13) {;
addEntity(e);
}
});
templateVMBox.find('.saved-entities').on('click', '.delete-entity', function() {
$(this).parents('.entity-wrapper').remove();
});
},
vmboxesMergeData: function(originalData, template) {
var self = this,
formData = monster.ui.getFormData('form_vmbox'),
mergedData = $.extend(true, {}, originalData, formData);
// Rebuild list of recipients from UI
mergedData.notify_email_address = [];
template.find('.saved-entities .entity-wrapper').each(function() {
mergedData.notify_email_address.push($(this).data('name'));
});
mergedData.not_configurable = !formData.extra.configurable;
if(mergedData.pin === '') {
delete mergedData.pin;
}
delete mergedData.extra;
return mergedData;
},
vmboxesFormatData: function(data) {
var self = this,
defaults = {
require_pin: true,
check_if_owner: true
},
formattedData = $.extend(true, {}, defaults, data.vmbox);
formattedData.extra = {};
return formattedData;
},
vmboxesFormatListData: function(results) {
var self = this,
formattedData = {
countVMBoxes: results.vmboxes.length,
vmboxes: results.vmboxes
},
mapUsers = {};
_.each(results.users, function(user) {
mapUsers[user.id] = user;
});
formattedData.vmboxes.sort(function(a,b) {
return parseInt(a.mailbox) > parseInt(b.mailbox) ? 1 : -1;
});
_.each(formattedData.vmboxes, function(vmbox) {
if(vmbox.hasOwnProperty('owner_id') && mapUsers.hasOwnProperty(vmbox.owner_id)) {
vmbox.friendlyOwnerName = mapUsers[vmbox.owner_id].first_name + ' ' + mapUsers[vmbox.owner_id].last_name;
}
else {
vmbox.friendlyOwnerName = '-';
}
});
return formattedData;
},
/* Utils */
vmboxesDeleteVmbox: function(voicemailId, callback) {
var self = this;
self.callApi({
resource: 'voicemail.delete',
data: {
accountId: self.accountId,
voicemailId: voicemailId,
data: {}
},
success: function(data) {
callback(data.data);
}
});
},
vmboxesGetEditData: function(id, callback) {
var self = this;
monster.parallel({
vmbox: function(callback) {
if(id) {
self.vmboxesGetVmbox(id, function(dataVmbox) {
callback(null, dataVmbox);
});
}
else {
callback(null, {});
}
}
},
function(error, results) {
var formattedData = self.vmboxesFormatData(results);
callback && callback(formattedData);
}
);
},
vmboxesGetVmbox: function(voicemailId, callbackSuccess, callbackError) {
var self = this;
self.callApi({
resource: 'voicemail.get',
data: {
accountId: self.accountId,
voicemailId: voicemailId
},
success: function(data) {
callbackSuccess && callbackSuccess(data.data);
},
error: function(data) {
callbackError && callbackError(data);
}
});
},
vmboxesSaveVmbox: function(vmboxData, callback) {
var self = this;
if(vmboxData.id) {
self.vmboxesUpdateVmbox(vmboxData, callback);
}
else {
self.vmboxesCreateVmbox(vmboxData, callback);
}
},
vmboxesCreateVmbox: function(vmboxData, callback) {
var self = this;
self.callApi({
resource: 'voicemail.create',
data: {
accountId: self.accountId,
data: vmboxData
},
success: function(data) {
callback(data.data);
}
});
},
vmboxesUpdateVmbox: function(vmboxData, callbackSuccess, callbackError) {
var self = this;
self.callApi({
resource: 'voicemail.update',
data: {
accountId: self.accountId,
data: vmboxData,
voicemailId: vmboxData.id
},
success: function(data) {
callbackSuccess && callbackSuccess(data.data);
},
error: function(data) {
callbackError && callbackError(data);
}
});
},
vmboxesGetData: function(callback) {
var self = this;
monster.parallel({
users: function(callback) {
self.callApi({
resource: 'user.list',
data: {
accountId: self.accountId,
filters: {
paginate: 'false'
}
},
success: function(dataUsers) {
callback && callback(null, dataUsers.data);
}
});
},
vmboxes: function(callback) {
self.callApi({
resource: 'voicemail.list',
data: {
accountId: self.accountId,
filters: {
paginate: 'false'
}
},
success: function(datavmboxes) {
callback(null, datavmboxes.data);
}
});
}
},
function(err, results) {
self.vmboxesFormatListData(results);
callback && callback(results);
}
);
}
};
return app;
});

+ 32
- 23
views/app.html View File

@ -1,6 +1,6 @@
<div id="voip_container" class="clearfix container-menu">
<div class="left-menu">
<div id="my_office" class="category simple separated">
<div id="myOffice" class="category simple separated">
<div class="title">
<i class="icon-home"></i>
<span class="title-text visible-desktop">{{ i18n.menuTitles.myOffice }}</span>
@ -8,6 +8,13 @@
</div>
<div class="category-group">
<div id="numbers" class="category">
<div class="title">
<i class="icon-th larger-margin"></i>
<span class="title-text visible-desktop">{{ i18n.menuTitles.numbers }}</span>
</div>
</div>
<div id="users" class="category">
<div class="title">
<i class="icon-telicon-seats"></i>
@ -22,39 +29,41 @@
</div>
</div>
<div id="devices" class="category">
<div class="title">
<i class="icon-telicon-voip-phone larger-margin"></i>
<span class="title-text visible-desktop">{{ i18n.menuTitles.devices }}</span>
</div>
</div>
<div id="numbers" class="category">
<div id="strategy" class="category">
<div class="title">
<i class="icon-th larger-margin"></i>
<span class="title-text visible-desktop">{{ i18n.menuTitles.numbers }}</span>
<i class="icon-telicon-home-phone"></i>
<span class="title-text visible-desktop">{{ i18n.menuTitles.mainNumber }}</span>
</div>
</div>
</div>
<div id="strategy" class="category simple separated">
<div class="title">
<i class="icon-telicon-home-phone"></i>
<span class="title-text visible-desktop">{{ i18n.menuTitles.mainNumber }}</span>
</div>
</div>
<div id="call_logs" class="category simple separated">
<div id="callLogs" class="category simple separated">
<div class="title">
<i class="icon-telicon-pbx"></i>
<span class="title-text visible-desktop">{{ i18n.menuTitles.callLogs }}</span>
</div>
</div>
<div id="feature_codes" class="category simple separated">
<div class="title">
<i class="icon-asterisk"></i>
<span class="title-text visible-desktop">{{ i18n.menuTitles.featureCodes }}</span>
<div class="category-group">
<div id="devices" class="category">
<div class="title">
<i class="icon-telicon-voip-phone larger-margin"></i>
<span class="title-text visible-desktop">{{ i18n.menuTitles.devices }}</span>
</div>
</div>
<div id="vmboxes" class="category">
<div class="title">
<i class="icon-telicon-voicemail larger-margin"></i>
<span class="title-text visible-desktop">{{ i18n.menuTitles.vmboxes }}</span>
</div>
</div>
<div id="featureCodes" class="category">
<div class="title">
<i class="icon-asterisk"></i>
<span class="title-text visible-desktop">{{ i18n.menuTitles.featureCodes }}</span>
</div>
</div>
</div>
</div>


+ 182
- 0
views/vmboxes-edit.html View File

@ -0,0 +1,182 @@
<div class="edit-vmbox" data-id="{{id}}">
<div class="title-bar clearfix">
<div class="vmbox-title pull-left">
<div class="vmbox-icon">
<i class="icon-telicon-voicemail"></i>
</div>
{{#if id}}
<div class="vmbox-model">{{ name }}</div>
{{else}}
<div class="vmbox-model">{{ i18n.vmboxes.new }}</div>
{{/if}}
</div>
<ul class="nav nav-pills pull-right">
<li class="tabs-main-selector main-section active">
<a class="tabs-selector change-section" data-section="basic" href="javascript:void(0)">{{ i18n.vmboxes.popupSettings.basicTitle }}</a>
</li>
<li class="tabs-main-selector main-section dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="javascript:void(0)">{{ i18n.vmboxes.popupSettings.advancedTitle }}
<b class="caret"></b>
</a>
<ul class="dropdown-menu pull-right">
<li><a class="tabs-selector change-section" data-section="options" href="javascript:void(0)"><i class="icon-ambulance"></i>{{ i18n.vmboxes.popupSettings.options.menuTitle }}</a></li>
<li><a class="tabs-selector change-section" data-section="recipients" href="javascript:void(0)"><i class="icon-envelope"></i>{{ i18n.vmboxes.popupSettings.recipients.menuTitle }}</a></li>
</ul>
</li>
</ul>
</div>
<div class="content">
<form id="form_vmbox" class="form-horizontal">
<div class="tabs-section active" data-section="basic">
<div class="control-group">
<label class="control-label" for="name">{{ i18n.vmboxes.popupSettings.basic.name.label }}</label>
<div class="controls">
<input type="text" id="name" name="name" value="{{ name }}">
</div>
</div>
<div class="control-group">
<label class="control-label" for="name">{{ i18n.vmboxes.popupSettings.basic.number.label }}</label>
<div class="controls">
<input type="text" id="mailbox" name="mailbox" value="{{ mailbox }}">
</div>
</div>
<div class="control-group">
<label class="control-label" for="name">{{ i18n.vmboxes.popupSettings.basic.pinNumber.label }}</label>
<div class="controls">
<input type="text" id="pin" name="pin" value="{{ pin }}">
</div>
</div>
</div>
<div class="tabs-section" data-section="options">
<div class="title">
{{ i18n.vmboxes.popupSettings.options.sectionTitle }}
</div>
<div class="control-group">
<label class="control-label" for="timezone">{{ i18n.vmboxes.popupSettings.options.timezone.label }}</label>
<div class="controls">
<select id="timezone" name="timezone" data-original_value="{{timezone}}"></select>
</div>
</div>
<div class="control-group">
<label class="control-input checkbox">
<div class="monster-checkbox" data-toggle="tooltip" data-placement="right" data-original-title="{{ i18n.vmboxes.popupSettings.options.alreadySetup.help }}">
<input type="checkbox" name="is_setup" id="is_setup" {{#if is_setup }}checked{{/if}} />
<label for="is_setup">{{ i18n.vmboxes.popupSettings.options.alreadySetup.label }}</label>
</div>
</label>
</div>
<div class="control-group">
<label class="control-input checkbox">
<div class="monster-checkbox" data-toggle="tooltip" data-placement="right" data-original-title="{{ i18n.vmboxes.popupSettings.options.requirePIN.help }}">
<input type="checkbox" name="require_pin" id="require_pin" {{#if require_pin }}checked{{/if}} />
<label for="require_pin">{{ i18n.vmboxes.popupSettings.options.requirePIN.label }}</label>
</div>
</label>
</div>
<div class="control-group">
<label class="control-input checkbox">
<div class="monster-checkbox" data-toggle="tooltip" data-placement="right" data-original-title="{{ i18n.vmboxes.popupSettings.options.autoLogin.help }}">
<input type="checkbox" name="check_if_owner" id="check_if_owner" {{#if check_if_owner }}checked{{/if}} />
<label for="check_if_owner">{{ i18n.vmboxes.popupSettings.options.autoLogin.label }}</label>
</div>
</label>
</div>
<div class="control-group">
<label class="control-input checkbox">
<div class="monster-checkbox" data-toggle="tooltip" data-placement="right" data-original-title="{{ i18n.vmboxes.popupSettings.options.skipGreetings.help }}">
<input type="checkbox" name="skip_greeting" id="skip_greeting" {{#if skip_greeting }}checked{{/if}} />
<label for="skip_greeting">{{ i18n.vmboxes.popupSettings.options.skipGreetings.label }}</label>
</div>
</label>
</div>
<div class="control-group">
<label class="control-input checkbox">
<div class="monster-checkbox" data-toggle="tooltip" data-placement="right" data-original-title="{{ i18n.vmboxes.popupSettings.options.skipInstructions.help }}">
<input type="checkbox" name="skip_instructions" id="skip_instructions" {{#if skip_instructions }}checked{{/if}} />
<label for="skip_instructions">{{ i18n.vmboxes.popupSettings.options.skipInstructions.label }}</label>
</div>
</label>
</div>
<div class="control-group">
<label class="control-input checkbox">
<div class="monster-checkbox" data-toggle="tooltip" data-placement="right" data-original-title="{{ i18n.vmboxes.popupSettings.options.deleteAfterNotify.help }}">
<input type="checkbox" name="delete_after_notify" id="delete_after_notify" {{#if delete_after_notify }}checked{{/if}} />
<label for="delete_after_notify">{{ i18n.vmboxes.popupSettings.options.deleteAfterNotify.label }}</label>
</div>
</label>
</div>
<div class="control-group">
<label class="control-input checkbox">
<div class="monster-checkbox" data-toggle="tooltip" data-placement="right" data-original-title="{{ i18n.vmboxes.popupSettings.options.configurable.help }}">
<input type="checkbox" name="extra.configurable" id="not_configurable" {{#unless not_configurable }}checked{{/unless}} />
<label for="not_configurable">{{ i18n.vmboxes.popupSettings.options.configurable.label }}</label>
</div>
</label>
</div>
</div>
<div class="tabs-section" data-section="recipients">
<div class="title">
{{ i18n.vmboxes.popupSettings.recipients.sectionTitle }}
</div>
<div class="helper">
<i class="icon-info-sign"></i>
{{ i18n.vmboxes.popupSettings.recipients.header }}
</div>
<div class="list-entities emails-list">
<div class="create-entity">
<div class="entity-wrapper placeholder">
<div class="create-text">
<i class="icon-plus-sign"></i>
{{ i18n.vmboxes.popupSettings.recipients.create }}
</div>
<div class="create-inputs">
{{ i18n.vmboxes.popupSettings.recipients.email }}
<input type="text" id="entity_name" name="extra.entityName" class="input-medium">
<button id="add_entity" class="btn btn-success">{{ i18n.add }}</button>
<a href="javascript:void(0);" id="cancel_entity">{{ i18n.cancel }}</a>
</div>
</div>
</div>
<div class="saved-entities">
</div>
</div>
</div>
</form>
</div>
<div class="actions clearfix">
{{#if id}}
<a id="delete_vmbox" class="monster-link"><i class="icon-trash icon-red"></i>{{ i18n.vmboxes.deleteVmbox }}</a>
{{/if}}
<div class="pull-right">
<a class="cancel-link monster-link blue" href="javascript:void(0);">{{ i18n.cancel }}</a>
<button type="button" class="btn btn-success save">
{{#if id}}
{{ i18n.saveChanges }}
{{else}}
{{ i18n.vmboxes.createVmbox }}
{{/if}}
</button>
</div>
</div>
</div>

+ 4
- 0
views/vmboxes-emailRow.html View File

@ -0,0 +1,4 @@
<div class="entity-wrapper" data-name="{{ name }}">
<span class="entity-title">{{ name }}</span>
<div class="delete-entity"><i class="icon-trash icon-red"></i></div>
</div>

+ 35
- 0
views/vmboxes-layout.html View File

@ -0,0 +1,35 @@
<div id="vmboxes_container">
<div class="vmboxes-header">
<div class="title">
{{ i18n.vmboxes.title }}
<span class="count-vmboxes">{{countVMBoxes}}</span>
</div>
<a class="monster-link add-vmbox">
<i class="icon-plus-sign"></i>
{{i18n.vmboxes.add }}
</a>
<span class="search-box pull-right">
<i class="icon-search"></i>
<input type="text" class="search-query" placeholder="{{ i18n.search }}..."></input>
</span>
</div>
<div class="vmboxes-grid">
<div class="grid-row title">
<div class="grid-cell number">{{ i18n.vmboxes.titleGrid.number }}</div>
<div class="grid-cell name">{{ i18n.vmboxes.titleGrid.name }}</div>
<div class="grid-cell owner">{{ i18n.vmboxes.titleGrid.owner }}</div>
<div class="grid-cell edit">{{ i18n.vmboxes.titleGrid.edit }}</div>
</div>
<div class="vmboxes-rows">
<div class="empty-search-row">
{{ i18n.devices.noMatchingVMBoxes }}
</div>
<div class="no-devices-row">
{{ i18n.devices.noVMBoxesConfigured }}
</div>
</div>
</div>
</div>

+ 19
- 0
views/vmboxes-row.html View File

@ -0,0 +1,19 @@
<div class="grid-row" data-id="{{id}}" data-search="{{name}} {{mailbox}} {{id}} {{friendlyOwnerName}}">
<div class="vmboxes-cells">
<div class="number grid-cell centered">
{{mailbox}}
</div>
<div class="name grid-cell">
{{name}}
</div>
<div class="owner grid-cell">
{{friendlyOwnerName}}
</div>
<div class="edit grid-cell centered">
<i class="icon-wrench settings"></i>
</div>
</div>
</div>

Loading…
Cancel
Save