<?xml version="1.0" encoding="UTF-8"?> <Module> <ModulePrefs title="Headless Gadget Servisbot TCP" description="ServisBOT Transcription Co Pilot" > <Require feature="settitle" /> <Require feature="dynamic-height" /> <Require feature="pubsub-2" /> <Require feature="setprefs" /> <Require feature="loadingindicator"> <Param name="manual-dismiss">false</Param> <Param name="loading-timeout">10</Param> </Require> </ModulePrefs> <!--Uncomment the below 3 lines if NOT hosting on Finesse server.--> <UserPref name="scheme" display_name="scheme" default_value=""/> <UserPref name="host" display_name="host" default_value=""/> <UserPref name="hostPort" display_name="hostPort" default_value=""/> <Content type="html"> <![CDATA[ <!DOCTYPE html> <!-- jQuery --> <!--<script type="text/javascript" src="/desktop/assets/js/jquery.min.js"></script>--? <!-- Finesse Library --> <!--<script type="text/javascript" src="/desktop/assets/js/finesse.js"></script>--> <!-- jQuery - uncomment if NOT hosting on Finesse server --> <script type="text/javascript" src="__UP_scheme__://__UP_host__:__UP_hostPort__/desktop/assets/js/jquery.min.js"></script> <!-- Finesse Library - uncomment if NOT hosting on Finesse server --> <script type="text/javascript" src="__UP_scheme__://__UP_host__:__UP_hostPort__/desktop/assets/js/finesse.js"></script> <!-- Gadget Business Logic --> <script type="text/javascript" src="HeadlessGadgetServisbotTCP.js"></script> <body class="claro"> </body> <script type="text/javascript"> gadgets.HubSettings.onConnect = function () { finesse.modules.HeadlessGadgetServisbotTCP.init(); }; </script> ]]> </Content> </Module>
/** * Test Gadget GOR * * Logs Cisco Finesse dialog events for voice calls and for ECE chats, so you * can see exactly when a chat starts, changes and ends. * * Based on the Cisco DevNet samples: github.com/CiscoDEVNet/finesse-Test-code * * Event sources: * - user.getDialogs() -> voice dialogs only * - new Media({id: 5000}) -> the ECE chat media, loaded directly by id * media.getMediaDialogs() -> ECE chat dialogs (new and already active) * * Note: onCollectionAdd only fires for dialogs created AFTER a collection has * loaded. Dialogs that already exist (e.g. after a browser refresh) are found * in the onLoad handlers. */ var finesse = finesse || {}; finesse.gadget = finesse.gadget || {}; finesse.container = finesse.container || {}; finesse.modules = finesse.modules || {}; finesse.modules.TestGadgetGOR = (function ($) { "use strict"; // ------------------------------------------------------------------ // Constants // ------------------------------------------------------------------ var GADGET_ID = "TestGadgetGOR"; var ECE_MEDIA_ID = "5000"; // Media Routing Domain id used by ECE chat // ------------------------------------------------------------------ // Module state // ------------------------------------------------------------------ var _logger; // finesse.cslogger.ClientLogger (set in init) var _user; // finesse.restservices.User var _dialogs; // voice dialogs collection var _eceMedia; // finesse.restservices.Media for the ECE chat media var _currentDialog = null; // voice dialog where this agent is ACTIVE // ------------------------------------------------------------------ // Helpers // ------------------------------------------------------------------ /** Log through the Finesse client logger, prefixed with the calling function. */ function _log(source, message) { if (_logger) { _logger.log(source + "(): " + message); } } /** Turn a failed REST response into a readable string. */ function _errText(rsp) { return rsp ? (rsp.status + " " + rsp.content) : "no response"; } /** Log the commonly useful properties of a dialog. */ function _logDialogDetails(source, dialog) { var callVars = dialog.getMediaProperties() || {}; _log(source, "dialog id: " + dialog.getId()); _log(source, "MediaType: " + dialog.getMediaType()); _log(source, "State: " + dialog.getState()); _log(source, "callType: " + (callVars.callType || "")); _log(source, "from (ani): " + dialog.getFromAddress()); _log(source, "to: " + dialog.getToAddress()); } /** * Find this agent's participant entry in a dialog (matched by extension). * @returns the participant object, or null if the agent isn't in the dialog */ function _getParticipant(dialog) { var participants = dialog.getParticipants(); var extension = _user.getExtension(); for (var key in participants) { if (participants.hasOwnProperty(key) && participants[key].mediaAddress === extension) { return participants[key]; } } return null; } // ------------------------------------------------------------------ // Voice dialogs (user.getDialogs) // ------------------------------------------------------------------ /** A voice dialog was added (or already existed when the gadget loaded). */ function _handleNewDialog(dialog) { _log("_handleNewDialog", "--------"); _logDialogDetails("_handleNewDialog", dialog); var participant = _getParticipant(dialog); _log("_handleNewDialog", "participant state: " + (participant ? participant.state : "none")); // Call variables may not have arrived yet, so keep listening for changes. dialog.addHandler("change", _updateDialog); } /** A voice dialog changed (call variables, participant state, etc.). */ function _updateDialog(dialog) { _log("_updateDialog", "--------"); _logDialogDetails("_updateDialog", dialog); var participant = _getParticipant(dialog); _log("_updateDialog", "participant state: " + (participant ? participant.state : "none")); // Remember the dialog the agent is actively on. if (participant && participant.state === "ACTIVE") { _currentDialog = dialog; } } /** A voice dialog ended. */ function _handleEndDialog(dialog) { _log("_handleEndDialog", "--------"); _logDialogDetails("_handleEndDialog", dialog); if (_currentDialog && _currentDialog.getId() === dialog.getId()) { _currentDialog = null; } } /** The voice dialog collection has loaded: process any existing dialogs. */ function _handleDialogsLoaded() { _log("_handleDialogsLoaded", "--------"); var collection = _dialogs.getCollection(); for (var id in collection) { if (collection.hasOwnProperty(id)) { _handleNewDialog(collection[id]); } } } // ------------------------------------------------------------------ // ECE chat dialogs (media 5000) // ------------------------------------------------------------------ /** A chat dialog was added (or already existed when the gadget loaded). */ function _handleNewMediaDialog(dialog) { _log("_handleNewMediaDialog", "--------"); _log("_handleNewMediaDialog", "dialog id: " + dialog.getId()); _log("_handleNewMediaDialog", "MediaType: " + dialog.getMediaType()); _log("_handleNewMediaDialog", "State: " + dialog.getState()); dialog.addHandler("change", _updateMediaDialog); } /** A chat dialog changed. */ function _updateMediaDialog(dialog) { _log("_updateMediaDialog", "--------"); _log("_updateMediaDialog", "dialog id: " + dialog.getId()); _log("_updateMediaDialog", "MediaType: " + dialog.getMediaType()); _log("_updateMediaDialog", "State: " + dialog.getState()); } /** A chat dialog ended. */ function _handleEndMediaDialog(dialog) { _log("_handleEndMediaDialog", "dialog id: " + dialog.getId()); } /** The chat dialogs have loaded: process any that are already active. */ function _handleMediaDialogsLoaded(mediaDialogs) { var collection = mediaDialogs.getCollection(); var count = 0; for (var id in collection) { if (collection.hasOwnProperty(id)) { count++; _handleNewMediaDialog(collection[id]); } } _log("_handleMediaDialogsLoaded", "existing chat dialogs: " + count); } /** The ECE media object has loaded: subscribe to its chat dialogs. */ function _handleEceMediaLoaded(media) { _log("_handleEceMediaLoaded", "media id: " + ECE_MEDIA_ID + ", name: " + media.getName()); // getMediaDialogs() throws unless the media is loaded, which is why // it is called from the media's onLoad handler. media.getMediaDialogs({ onCollectionAdd: _handleNewMediaDialog, onCollectionDelete: _handleEndMediaDialog, onLoad: _handleMediaDialogsLoaded, onError: function (rsp) { _log("_handleEceMediaLoaded", "dialogs ERROR: " + _errText(rsp)); } }); } // ------------------------------------------------------------------ // User events // ------------------------------------------------------------------ /** The user object has loaded: start listening for dialogs. */ function _handleUserLoad() { _log("_handleUserLoad", "agent state: " + _user.getState()); // 1. Voice dialogs _dialogs = _user.getDialogs({ onCollectionAdd: _handleNewDialog, onCollectionDelete: _handleEndDialog, onLoad: _handleDialogsLoaded }); // 2. ECE chat dialogs. Load the ECE media directly by id; its parent // is the user, so the REST path is .../User/<id>/Media/5000 _eceMedia = new finesse.restservices.Media({ id: ECE_MEDIA_ID, parentObj: _user, onLoad: _handleEceMediaLoaded, onError: function (rsp) { _log("_handleUserLoad", "ECE media ERROR: " + _errText(rsp)); } }); } /** Any change to the user (e.g. agent state). */ function _handleUserChange() { _log("_handleUserChange", "agent state: " + _user.getState()); } // ------------------------------------------------------------------ // Public API // ------------------------------------------------------------------ return { /** Performs all initialization for this gadget. */ init: function () { var config = finesse.gadget.Config; // Set up the Finesse client logger. The gadget id is included in each message. _logger = finesse.cslogger.ClientLogger; _logger.init(gadgets.Hub, GADGET_ID, config); _log("init", "Initializing..."); // Initialise ClientServices with the current config, then load the user. finesse.clientservices.ClientServices.init(config, false); _user = new finesse.restservices.User({ id: config.id, onLoad: _handleUserLoad, onChange: _handleUserChange }); // When this gadget's tab becomes visible, re-adjust the height. // adjustHeight only works on a visible tab, so without this the // gadget is the wrong size on load until the page is refreshed. var containerServices = finesse.containerservices.ContainerServices.init(); containerServices.addHandler( finesse.containerservices.ContainerServices.Topics.ACTIVE_TAB, function () { _log("init", "Gadget is now visible"); gadgets.window.adjustHeight(); } ); containerServices.makeActiveTabReq(); _log("init", "Initialization finished."); } }; }(jQuery));