Adding a floating frame into Sugar

Sugar's Single Page Architecture

Sugar relies on a single page architecture (SPA) for the Sidecar framework. But when a user navigates across the Sugar application (for example, when switching to another Sugar module), while the page is not refreshed, you will find that the majority of the HTML on the page is still re-rendered based upon the newly selected layout. This is done to not only change the style or configuration of the view (ex. List View → Record View) but also to update the context and configuration for the dashboard panel.

But not everything changes - the footer and header of the application remain fixed so they can serve as navigational anchors for Sugar users. This is an important use case but there are certainly others.

Telephony integration scenarios

A common set of integrations that are built for Sugar involve integrating a phone system for use by customer service organizations. This can vary from simple "click to dial" softphone functionality to full blown multi-channel call center capability where an agent handles phone, SMS, and e-mail inquiries at the same time.

A typical in-bound call process follows:

Step 1) A customer calls support desk with an inquiry

Step 2) The call is routed to an available support agent desktop

Step 3) The agent desktop displays current customer information

Step 4) The service agent handles customer inquiry

Step 5) The interaction details are logged to the customer record


While the call is active, it is typically necessary to have a persistent display of the call's status and caller information. The service agent may need to be able to review CRM data across multiple modules without losing the call's context.

This need is not addressed by customizing standard Sidecar Record or List layouts because they aren't fixed. An alternative could be to open a pop-up windows but that is a pretty crappy user experience.

There are better alternatives. Users expect to be able to work within the Sugar application and this can be accommodated by adding a floating frame to the Sugar user interface that will serve our needs.

Floating Div Action Building Block

We have created a package that provides a prescribed pattern for handling persistent content within the Sugar UI using a floating frame. This frame can be configured to iframe web content from an external system or as a basis for a native Sidecar component. There are multiple telephony solutions in the Sugar ecosystem that use variations on this approach.

We will dig into some of the code below.

Footer contribution via Sidecar Extension

We can add the Call button seen in the screenshot above using a Sidecar Extension for a new custom Sidecar View. We will talk about this new click-to-call view (ClickToCallView) later.custom/Extension/application/Ext/clients/base/layouts/footer/addClickToCallAction.php


<?php

// Copyright 2016 SugarCRM Inc.  Licensed by SugarCRM under the Apache 2.0 license.

//  Append new View to Footer layout's list of components

$viewdefs['base']['layout']['footer']['components'][] = array (
    'view' => 'click-to-call',
);

The ClickToCallView toggle button

The toggle button that appears in footer is implemented as part of our new custom ClickToCallView within custom/clients/base/views/click-to-call/click-to-call.js and custom/clients/base/views/click-to-call/click-to-call.hbs. Since this Sidecar View is attached to the footer, it will be persistent as the user navigates. We can conveniently use it to manage the lifecycle of our "popup" frame to ensure it is only loaded once. Instead of removing the pop-up frame completely when a user closes it, we will simply hide it from view so that it does not need to be recreated later.


...

    events: {

        //On click of our "button" element

        'click [data-action=open_phone]': 'togglePopup',

    },

    // tagName attribute is inherited from Backbone.js.

    // We set it to "span" instead of default "div" so that our "button" element is displayed inline.

    tagName: "span",

    // Used to keep track of Popup since it is not attached to this View's DOM

    $popup: undefined,

    /**

     * Toggle the display of the popup.  Called when the phone icon is pressed in the footer of the page.

     */


    togglePopup: function () {

        //Toggle active status on button in footer

        var $button = this.$('[data-action="open_phone"]');

        $button.toggleClass('active');

        //Create popup if necessary, otherwise just toggle the hidden class to hide/show.

        if (!this.$popup) {

            this._createPopup();

        } else {

            this.$popup.toggleClass('hidden');

        }

    },

...


{{! Copyright 2016 SugarCRM Inc.  Licensed by SugarCRM under the Apache 2.0 license. }}

{{!

    Define HTML for our new button.  We will mimic the style of other buttons

    in the footer so we remain consistent.

}}

<button data-action="open_phone" class="btn btn-invisible" aria-label="{{str "Call"}}" role="link" type="button">

    <i class="fa fa-phone icon-phone"></i><span class="action-label"> {{str "Call"}}</span>

</button>

The floating frame

Sugar does not provide a popup frame component out of the box, so we can create one from scratch with our own Handlebars templates for the HTML and necessary CSS. We also use the Draggable jQuery UI plug-in that is already included with Sidecar to allow users to reposition the frame as they want.

Our JavaScript code will lazy load in the CSS to the HEAD section of the page and append our popup frame to the main content DIV element when the Call button is toggled the very first time.custom/clients/base/views/click-to-call/click-to-call.js


...

    /**

     * Used to create Popup as needed. Avoid calling this directly, should only need to be called once.

     * @private

     */


    _createPopup: function () {

        var popupCss = app.template.get("click-to-call.popup-css");

        // We need to load some custom CSS, this is an easy way to do it without having to edit custom.less

        $('head').append(popupCss());

        var popup = app.template.get("click-to-call.popup")(this);

        // Add to main content pane of screen

        $('#sidecar').append(popup);

        this.$popup = $('#sidecar').find('div.cti-popup');

        // Hide pop up on click of X (close button)

        this.$popup.find('[data-action=close]').click(_.bind(this._closePopup, this));

        // Make pop up draggable using existing jQuery UI plug-in

        this.$popup.draggable();

    },

...

custom/clients/base/views/click-to-call/popup.hbs


{{! Copyright 2016 SugarCRM Inc.  Licensed by SugarCRM under the Apache 2.0 license. }}

<div class="cti-popup">

<div class="cti-popup-header">

        <strong>CTI Window</strong>

        <a class="cti-close pull-right" data-action="close"><i class="fa fa-times fa-large"></i></a></div>

<div class="cti-popup-content">

        <iframe src="{{meta.iframeSrc}}"></iframe></div>

</div>

custom/clients/base/views/click-to-call/popup-css.hbs

{{! Copyright 2016 SugarCRM Inc.  Licensed by SugarCRM under the Apache 2.0 license. }}

<style type="text/css">

    .cti-popup {

        position: fixed;

        top: 50%;

        left: 50%;

        z-index: 1050;

        max-height: 500px;

        background-color: #f6f6f6;

        border: 1px solid #cfcfcf;

        *border: 1px solid #999;

        /* IE6-7 */

        -webkit-border-radius: 4px;

        -moz-border-radius: 4px;

        border-radius: 4px;

        -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);

        -moz-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);

        box-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);

        -webkit-background-clip: padding-box;

        -moz-background-clip: padding-box;

        background-clip: padding-box;

    }

    .cti-popup-header {

        background-color: #f6f6f6;

        padding: 10px 15px;

        border-bottom: 1px solid #f5f5f5;

    }

    .cti-close{

        position: relative;

        top: -2px;

    }

</style>

Full example available in Github

You can find the full example as a module loadable package you can build yourself on Github. Just find the Floating Div Action package that is part of the SugarCRM Building Blocks repository. As of today, I have tested this package with Sugar 7.6 and Sugar 7.7.

Let me know what you think!

  • I have finally completed the call control portion of the application I'm creating.  I can now successfully make/receive/transfer and conference calls using Mitel's OIG Server interface.  I have also pulled the CTI GUI into a floating iframe with an appropriate button in the footer section of the Sugar GUI to open/close the iframe.  Now it's time to actually interact with Sugar.  My question is related to incoming calls.   Upon receiving the calling name information from the incoming call, I will use the appropriate REST endpoint (/globalsearch/GET) which returns a list of records that I will display inside the iframe.  So far so good.  When the user clicks on one of the records in the iframe, I would like to display the selected record in the Sugar GUI (ie same behavior as if they had clicked to display a record from a list view).   

    I found some example code regarding how to detect a click event on a cross domain iframe using "window.addEventListner".  Not sure if it works or not, but if I can get the event back to the parent (Sugar GUI), then I can take action.  My question is what action should I take that will result in display of the selected record?   The development guide made mention of Context Events that I thought might be useful in this situation.  Do you have a recommendation?

  • Dashlets can definitely be made to work.

    The issue is that every time you load a new screen, we would load a new dashboard. So you'd have to configure dashboards for every screen that the user would visit while on a call. You'd also have to wait for the dashlets to reload each screen change. In the video, of the SF integration, I didn't notice any reloads of the screen. I think they intentionally edited it to prevent you from seeing the MiVoice panel being reloaded over and over again.

    Having a floating frame is easier and provides a better user experience, in my opinion.

  • I am embarking on my first Sugar CRM integration.  It will be a telephony integration (Mitel's OIG).   The first version will have the simple screen pop and click to dial functionality.  Eventually more functionality will be added.... something similiar to MiVoice Integration with Salesforce - YouTube .   As I was reading through all the wonderful documentation, my first thought was to create a dashlet.  However, I found this post and was wondering if the floating frame is still recommended.  

    Thank you,

    Denise

  • Comment originally made by Matthew Marum.

    Typically, I would recommend a drawer when you need a large canvas view on an existing module layout like the Record View.

    http://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_7.6/API/Sidecar/Drawers/

  • Comment originally made by David Wahl.

    Matt, one of the challenges we are facing right now on an implementation is to create custom "report" type data to the user while he is on an account page. Unfortunately, the screen size can sometimes render these dashlets too small to be fully useful. Would you recommend a window like this to expand out a dashlet in the intelligence panel for better viewing? If not, is there another approach?