diff --git a/src/apps/callflows/app.js b/src/apps/callflows/app.js index 7cdcd6c..85368d5 100644 --- a/src/apps/callflows/app.js +++ b/src/apps/callflows/app.js @@ -10,7 +10,7 @@ define(function(require) { 'conference', 'device', 'directory', - 'eavesdrop', + 'eavesdrop', 'faxbox', 'featurecodes', 'groups', @@ -606,11 +606,16 @@ define(function(require) { formattedData.extra.isShoutcast = false; formattedData.extra.preflowCallflows = []; + var numbers, + patterns _.each(formattedData.callflows, function(callflow) { - if (callflow.featurecode === false && callflow.numbers && callflow.numbers.length && callflow.numbers.indexOf('no_match') < 0) { + numbers = callflow.numbers; + patterns = callflow.patterns; + if (callflow.featurecode === false + && (numbers.length > 0 || patterns.length > 0)) { formattedData.extra.preflowCallflows.push({ id: callflow.id, - friendlyName: callflow.name || callflow.numbers.toString() + friendlyName: callflow.name || numbers.concat(patterns).join(', ') }); } }); @@ -1023,19 +1028,20 @@ define(function(require) { _.each(data.data, function(callflow) { var formattedNumbers = _.map(callflow.numbers || '-', function(number) { - return _.startsWith('+', number) - ? monster.util.formatPhoneNumber(number) - : number; - }), - listNumbers = formattedNumbers.toString(), - isFeatureCode = callflow.featurecode !== false && !_.isEmpty(callflow.featurecode); + return _.startsWith('+', number) + ? monster.util.formatPhoneNumber(number) + : number; + }); + + var listNumbersAndPatterns = _.merge(formattedNumbers, callflow.patterns).join(', '); + var isFeatureCode = callflow.featurecode !== false && !_.isEmpty(callflow.featurecode); if (!isFeatureCode) { if (callflow.name) { - callflow.description = listNumbers; + callflow.description = listNumbersAndPatterns; callflow.title = callflow.name; } else { - callflow.title = listNumbers; + callflow.title = listNumbersAndPatterns; } formattedList.push(callflow); @@ -1051,6 +1057,20 @@ define(function(require) { return data; }, + callflowsGetModulesByNameInCallflow: function (flow, moduleName, resultArr) { + var self = this; + resultArr = resultArr || []; + + if(flow.module === moduleName) { + resultArr.push(flow.data); + } + + for(var k in flow.children) if(flow.children.hasOwnProperty(k)) { + self.callflowsGetModulesByNameInCallflow(flow.children[k], moduleName, resultArr); + } + return resultArr; + }, + editCallflow: function(data) { var self = this; @@ -1078,14 +1098,28 @@ define(function(require) { self.flow.name = callflow.name; self.flow.contact_list = { exclude: 'contact_list' in callflow ? callflow.contact_list.exclude || false : false }; self.flow.caption_map = callflow.metadata; - - if (callflow.flow.module !== undefined) { - self.flow.root = self.buildFlow(callflow.flow, self.flow.root, 0, '_'); - } - self.flow.numbers = callflow.numbers || []; + self.flow.patterns = callflow.patterns || []; - self.repaintFlow(); + var buildAndRepaintFlow = function () { + if (callflow.flow.module !== undefined) { + self.flow.root = self.buildFlow(callflow.flow, self.flow.root, 0, '_'); + } + self.repaintFlow(); + }; + + var callflowModulesInFlow = self.callflowsGetModulesByNameInCallflow(callflow.flow, 'callflow', []); + if(callflowModulesInFlow.length > 0) { + self.callflowsExtendMetadataOfCallflowModules(callflowModulesInFlow, function (callflows) { + for (var c in callflows) if (callflows.hasOwnProperty(c)) { + self.flow.caption_map[callflows[c].id].numbers = callflows[c].numbers; + self.flow.caption_map[callflows[c].id].patterns = callflows[c].patterns; + } + buildAndRepaintFlow(); + }) + } else { + buildAndRepaintFlow(); + } } }); } else { @@ -1098,6 +1132,48 @@ define(function(require) { self.renderTools(); }, + callflowsGetCallflow: function (id, callback) { + var self = this; + + self.callApi({ + resource: 'callflow.get', + data: { + accountId: self.accountId, + callflowId: id + }, + success: function(callflow) { + callflow = callflow.data; + + if(typeof(callback) === 'function') { + callback(callflow); + } + }, + error: function(data) { + console.log('Error while getting callflow'); + console.log(data); + } + }); + }, + + callflowsExtendMetadataOfCallflowModules: function (callflowsList, callback) { + var self = this; + var requestsList = {}; + for (var i = 0, len = callflowsList.length; i< len; i++) { + requestsList[callflowsList[i].id] = (function(){ + var callflowId = callflowsList[i].id; + return function (callback) { + self.callflowsGetCallflow(callflowId, function (callflow) { + callback(null, callflow); + }) + } + })(); + } + + monster.parallel(requestsList, function(error, results) { + callback && callback(results); + }); + }, + renderButtons: function() { var self = this, buttons = $(self.getTemplate({ @@ -1107,11 +1183,20 @@ define(function(require) { $('.buttons').empty(); $('.save', buttons).click(function() { - if (self.flow.numbers && self.flow.numbers.length > 0) { - self.save(); - } else { + var numbersAndPatternsNotFound = self.flow.numbers.length === 0 && self.flow.patterns.length === 0; + var numbersAndPatternsTogether = self.flow.numbers.length > 0 && self.flow.patterns.length > 0; + + if(numbersAndPatternsNotFound) { monster.ui.alert(self.i18n.active().oldCallflows.invalid_number + '

' + self.i18n.active().oldCallflows.please_select_valid_number); + return; } + + if(numbersAndPatternsTogether) { + monster.ui.alert(self.i18n.active().callflows.messages.numbers_and_patterns_together_error); + return; + } + + self.save(); }); $('.delete', buttons).click(function() { @@ -1200,6 +1285,7 @@ define(function(require) { self.flow.root = self.branch('root'); // head of the flow tree self.flow.root.key = 'flow'; self.flow.numbers = []; + self.flow.patterns = []; self.flow.caption_map = {}; self.formatFlow(); }, @@ -1437,6 +1523,10 @@ define(function(require) { $.each(flow.numbers, function(key, value) { s_flow += '|' + value; }); + s_flow += '|PATTERNS'; + $.each(flow.patterns, function(key, value) { + s_flow += '|' + value; + }); s_flow += '|NODES'; $.each(flow.nodes, function(key, value) { s_flow += '|' + key + '::'; @@ -1476,7 +1566,7 @@ define(function(require) { flow.root = self.branch('root'); flow.root.key = 'flow'; - flow.numbers = []; + flow.patterns = []; flow.caption_map = {}; flow.root.index(0); flow.nodes = flow.root.nodes(); @@ -1492,6 +1582,7 @@ define(function(require) { flow.nodes = flow.root.nodes(); flow.numbers = callflow.numbers || []; + flow.patterns = callflow.patterns || []; //prepare html from callflow @@ -1512,16 +1603,23 @@ define(function(require) { } })); - for (var counter, size = flow.numbers.length, j = Math.floor((size) / 2) + 1, i = 0; i < j; i++) { + var numbersFormatted = _.map(flow.numbers, function(number) { + return _.startsWith('+', number) + ? monster.util.formatPhoneNumber(number) + : number; + }); + var numbersAndPatterns = numbersFormatted.concat(flow.patterns); + for (var counter, size = numbersAndPatterns.length, j = Math.floor((size) / 2) + 1, i = 0; i < j; i++) { counter = i * 2; - var numbers = flow.numbers.slice(counter, (counter + 2 < size) ? counter + 2 : size), - row = $(self.getTemplate({ - name: 'rowNumber', - data: { - numbers: numbers - } - })); + var currentNumbersAndPatterns = numbersAndPatterns.slice(counter, (counter + 2 < size) ? counter + 2 : size); + + var row = $(self.getTemplate({ + name: 'rowNumber', + data: { + numbers: currentNumbersAndPatterns + } + })); node_html .find('.content') @@ -1603,20 +1701,24 @@ define(function(require) { }); }); - for (var counter, size = self.flow.numbers.length, j = Math.floor((size) / 2) + 1, i = 0; i < j; i++) { + var numbersFormatted = _.map(self.flow.numbers, function(number) { + return _.startsWith('+', number) + ? monster.util.formatPhoneNumber(number) + : number; + }); + + var numbersAndPatterns = numbersFormatted.concat(self.flow.patterns); + for (var counter, size = numbersAndPatterns.length, j = Math.floor((size) / 2) + 1, i = 0; i < j; i++) { counter = i * 2; - var numbers = self.flow.numbers.slice(counter, (counter + 2 < size) ? counter + 2 : size), - row = $(self.getTemplate({ - name: 'rowNumber', - data: { - numbers: _.map(numbers, function(number) { - return _.startsWith('+', number) - ? monster.util.formatPhoneNumber(number) - : number; - }) - } - })); + var currentNumbersAndPatterns = numbersAndPatterns.slice(counter, (counter + 2 < size) ? counter + 2 : size); + + var row = $(self.getTemplate({ + name: 'rowNumber', + data: { + numbers: currentNumbersAndPatterns + } + })); node_html .find('.content') @@ -1646,9 +1748,7 @@ define(function(require) { title: self.i18n.active().oldCallflows.add_number }); - monster.ui.chosen(popup_html.find('#list_numbers'), { - width: '160px' - }); + monster.ui.chosen(popup_html.find('#list_numbers'), {}); // Have to do that so that the chosen dropdown isn't hidden. popup_html.parent().css('overflow', 'visible'); @@ -1673,15 +1773,21 @@ define(function(require) { }); }; - $('.extensions_content', popup).hide(); + $('.js-add-number-content', popup).hide(); + $('.js-list-numbers-content', popup).show(); $('input[name="number_type"]', popup).click(function() { - if ($(this).val() === 'your_numbers') { - $('.list_numbers_content', popup).show(); - $('.extensions_content', popup).hide(); - } else { - $('.extensions_content', popup).show(); - $('.list_numbers_content', popup).hide(); + $('.js-add-number-content', popup).hide(); + switch($(this).val()) { + case 'your_numbers': + $('.js-list-numbers-content', popup).show(); + break; + case 'extension': + $('.js-extensions-content', popup).show(); + break; + default: // case 'pattern': + $('.js-pattern-content', popup).show(); + break; } }); @@ -1714,38 +1820,23 @@ define(function(require) { $('.add_number', popup).click(function(event) { event.preventDefault(); - var number = $('input[name="number_type"]:checked', popup).val() === 'your_numbers' ? $('#list_numbers option:selected', popup).val() : $('#add_number_text', popup).val(); - - if (number !== 'select_none' && number !== '') { - self.flow.numbers.push(number); - popup.dialog('close'); - - self.repaintFlow(); - - if (self.tour - && $('#ws_callflow .number_column').not('.js-add-number').length === 1) { - if (self.tour.ended()) { - self.tour.restart(); - } - if (self.tour.getCurrentStep() !== 2) { - self.tour.goTo(2); - } - } - } else { - monster.ui.alert(self.i18n.active().oldCallflows.you_didnt_select); - } + self.callflowsAddNumberOrPattern(this, popup); }); }); }); $('.number_column .delete', node_html).click(function() { - var number = $(this).parent('.number_column').data('number') + '', - index = $.inArray(number, self.flow.numbers); + var numberOrPattern = $(this).parent('.number_column').data('number') + ''; + var indexInNumbers = $.inArray(numberOrPattern, self.flow.numbers); + var indexInPatterns = $.inArray(numberOrPattern, self.flow.patterns); - if (index >= 0) { - self.flow.numbers.splice(index, 1); + if(indexInNumbers !== -1) { + self.flow.numbers.splice(indexInNumbers, 1); } + if(indexInPatterns !== -1) { + self.flow.patterns.splice(indexInPatterns, 1); + } self.repaintFlow(); }); } else { @@ -1915,14 +2006,87 @@ define(function(require) { }); $('.node-options .jump', layout).click(function() { - var $this = $(this), - callflowId = $this.attr('id'); - self.editCallflow({ id: callflowId }); - }); + var $this = $(this), + callflowId = $this.attr('id'); + self.editCallflow({ id: callflowId }); + }); return layout; }, + callflowsAddNumberOrPattern: function (button, popup) { + var self = this, + numberType = $('input[name="number_type"]:checked', popup).val(), + pattern = '', + number = '', + $messageContainer = $('.js-message-container', popup), + togetherErrorMessage = self.i18n.active().callflows.messages.numbers_and_patterns_together_error; + + var showNextTourStep = function () { + if (self.tour + && $('#ws_callflow .number_column').not('.js-add-number').length === 1) { + if (self.tour.ended()) { + self.tour.restart(); + } + if (self.tour.getCurrentStep() !== 2) { + self.tour.goTo(2); + } + } + }; + + switch(numberType) { + case 'your_numbers': + number = $('#list_numbers option:selected', popup).val(); + break; + case 'extension': + number = $('#add_number_text', popup).val(); + break; + default: // case 'pattern': + pattern = $('#add_pattern_text', popup).val(); + break; + } + + if (number && number === 'select_none') { + monster.ui.alert(self.i18n.active().oldCallflows.you_didnt_select); + } + + if (number) { + if (self.flow.patterns.length > 0) { + $messageContainer.empty(); + self.callflowsInsertAlertMessage($messageContainer, 'warning', togetherErrorMessage); + return; + } + self.flow.numbers.push(number); + self.repaintFlow(); + showNextTourStep(); + popup.dialog('close'); + return; + } + + if (pattern) { + if (self.flow.numbers.length > 0) { + $messageContainer.empty(); + self.callflowsInsertAlertMessage($messageContainer, 'warning', togetherErrorMessage); + return; + } + self.flow.patterns.push(pattern); + self.repaintFlow(); + showNextTourStep(); + popup.dialog('close'); + } + }, + + callflowsInsertAlertMessage: function ($target, type, message, additionalClasses) { + var validTypes = ['info', 'question', 'error', 'warning']; + type = typeof type === 'string' && validTypes.indexOf(type) >= 0 ? type : 'info'; + var templateData = { + className: additionalClasses ? 'callflows-message ' + additionalClasses : 'callflows-message', + content: message + }; + var template = monster.template(monster.apps.core, 'monster-text-' + type, templateData, false, false, true); + $target.append(template); + }, + renderBranch: function(branch) { var self = this, flow = $(self.getTemplate({ @@ -2133,14 +2297,23 @@ define(function(require) { }, save: function() { - var self = this; + var self = this, + haveNumbers = self.flow.numbers && self.flow.numbers.length > 0, + havePatterns = self.flow.patterns && self.flow.patterns.length > 0; - if (self.flow.numbers && self.flow.numbers.length > 0) { + if (haveNumbers || havePatterns) { var data_request = { - numbers: self.flow.numbers, flow: (self.flow.root.children[0] === undefined) ? {} : self.flow.root.children[0].serialize() }; + if(haveNumbers) { + data_request.numbers = self.flow.numbers; + } + + if(havePatterns) { + data_request.patterns = self.flow.patterns; + } + if (self.flow.name !== '') { data_request.name = self.flow.name; } else { diff --git a/src/apps/callflows/i18n/en-US.json b/src/apps/callflows/i18n/en-US.json index 298f3b7..3591e04 100644 --- a/src/apps/callflows/i18n/en-US.json +++ b/src/apps/callflows/i18n/en-US.json @@ -16,6 +16,10 @@ } }, "callflows": { + "messages": { + "numbers_and_patterns_together_error": "A callflow should include a list of numbers or regex patterns only" + }, + "pattern": "Pattern", "addCallflow": "Add Callflow", "searchDatabase": "Search Database", "buyNumbers": "Buy Numbers", @@ -1372,7 +1376,7 @@ "giving_a_name_to_a_callflow": "Giving a name to a callflow isn't mandatory. Leave the field blank and the callflow will be displayed in the left listing as the list of numbers used in this callflow.", "popup_title": "Edit Callflow Name", "callflow_preview_title": "Callflow Preview", - "add_number": "Add number", + "add_number": "Add number or pattern", "add_a_number": "Add a number", "available_numbers": "Spare Numbers", "extension": "Extension", diff --git a/src/apps/callflows/style/app.css b/src/apps/callflows/style/app.css index 98f00d9..4ba8912 100644 --- a/src/apps/callflows/style/app.css +++ b/src/apps/callflows/style/app.css @@ -454,8 +454,10 @@ padding-right: 0px; } +#ws_callflow .details a, .callflow-preview .details a { - color: #22A5FF; + color: white; + text-decoration: underline; } .callflow-preview * { @@ -1913,6 +1915,41 @@ background: url('static/images/callflows-drag-and-drop.gif') no-repeat; } +.callflows-form.form-inline .form-label-wrapper { + display: inline-block; + vertical-align: top; + text-align: left; + width: 160px; + margin-right: 0; + margin-bottom: 13px; + padding-top: 10px; +} + +.callflows-form.form-inline .form-field-wrapper { + display: inline-block; + vertical-align: top; +} + +.callflows-message-container { + padding: 10px 20px 20px; +} + +.callflows-message { + border: 1px solid #22A5FF; + background: #22A5FF; +} + +.callflows-message .text-wrapper { + color: white; +} + +.help-box .wrapper-icon { + background: white; +} + +.callflows-message .fa { + color: #22A5FF !important; +} /* * Bootstrap guide tour - override styles diff --git a/src/apps/callflows/submodules/misc/misc.js b/src/apps/callflows/submodules/misc/misc.js index 72a0e04..102a934 100644 --- a/src/apps/callflows/submodules/misc/misc.js +++ b/src/apps/callflows/submodules/misc/misc.js @@ -87,14 +87,19 @@ define(function(require) { var id = node.getMetadata('id'), return_value = ''; - if (id in caption_map) { - if (caption_map[id].hasOwnProperty('name')) { + var callflow, + numbers, + patterns; + if (id in caption_map && caption_map.hasOwnProperty(id)) { + callflow = caption_map[id]; + if (callflow.name) { return_value = caption_map[id].name; - } else if (caption_map[id].hasOwnProperty('numbers')) { - return_value = caption_map[id].numbers.toString(); + } else { + numbers = callflow.numbers || []; + patterns = callflow.patterns || []; + return_value = numbers.concat(patterns).join(', '); } } - return return_value; }, edit: function(node, callback) { @@ -111,8 +116,13 @@ define(function(require) { $.each(data.data, function() { if (!this.featurecode && this.id !== self.flow.id) { - this.name = this.name ? this.name : ((this.numbers) ? this.numbers.toString() : self.i18n.active().oldCallflows.no_numbers); - + if (!this.name) { + if(this.numbers && this.numbers.length > 0) { + this.name = this.numbers ? this.numbers.join(', ') : self.i18n.active().oldCallflows.no_numbers + } else if (this.patterns && this.patterns.length > 0) { + this.name = this.patterns ? this.patterns.join(', ') : self.i18n.active().oldCallflows.no_numbers + } + } _data.push(this); } }); @@ -503,23 +513,23 @@ define(function(require) { }); } }, - 'webhook[]': { - name: self.i18n.active().callflows.webhook.title, - icon: 'upload', - category: self.i18n.active().oldCallflows.advanced_cat, - module: 'webhook', - tip: self.i18n.active().callflows.webhook.tip, - data: {}, - rules: [], - isUsable: 'true', - weight: 170, - caption: function() { - return ''; - }, - edit: function(node, callback) { - self.miscRenderEditWebhook(node, callback); - } - }, + 'webhook[]': { + name: self.i18n.active().callflows.webhook.title, + icon: 'upload', + category: self.i18n.active().oldCallflows.advanced_cat, + module: 'webhook', + tip: self.i18n.active().callflows.webhook.tip, + data: {}, + rules: [], + isUsable: 'true', + weight: 170, + caption: function() { + return ''; + }, + edit: function(node, callback) { + self.miscRenderEditWebhook(node, callback); + } + }, 'set_alert_info[]': { name: self.i18n.active().callflows.setAlertInfo.name, icon: 'play', @@ -1258,13 +1268,13 @@ define(function(require) { })); if ($('#media_selector option:selected', popup_html).val() === undefined - || $('#media_selector option:selected', popup_html).val() === 'null') { + || $('#media_selector option:selected', popup_html).val() === 'null') { $('#edit_link', popup_html).hide(); } $('#media_selector', popup_html).change(function() { if ($('#media_selector option:selected', popup_html).val() === undefined - || $('#media_selector option:selected', popup_html).val() === 'null') { + || $('#media_selector option:selected', popup_html).val() === 'null') { $('#edit_link', popup_html).hide(); } else { $('#edit_link', popup_html).show(); diff --git a/src/apps/callflows/views/addNumber.html b/src/apps/callflows/views/addNumber.html index a541493..940a662 100644 --- a/src/apps/callflows/views/addNumber.html +++ b/src/apps/callflows/views/addNumber.html @@ -1,45 +1,47 @@
-
+