Global Action Menus and Drawers in Sugar 7

Post originally written by John Mertic.

Editor's Note: This blog post comes from Bill Convis of SierraCRM, and talks about how his team worked with our top notch engineering team to find a way to add action menu items across multiple modules. Big thanks to Bill for the writeup, and Peter DeMartini of SierraCRM, and David Wheeler of SugarCRM for helping form the solution.

With the release of SugarCRM 7 came new challenges and opportunities for SugarCRM technology partners. An entirely new paradigm was offered for solution providers to add new features to the power of SugarCRM. Process Manager Enterprise (PM) from SierraCRM, a workflow solution that augments SugarCRM’s existing workflow, was being updated to take advantage of the new architecture.

One of the features to be added to the new release of PM was the ability to see all the processes for a single object. Our intent was to show both processes that had been completed and process that were currently active.

After reviewing the options, a decision was made to add an “action item” to a record view to display a drawer with a listing view of the processes for that record.

We approached John Mertic at SugarCRM and asked him if there was an extensible framework for action buttons, as we wanted to build a solution that was both upgrade safe and would be global across all modules. He suggested we meet with the engineers at SugarCon.

At the SugarCon 2014 conference in San Francisco, Sierra’s senior developer, Peter DeMartini, met up with SugarCRM Engineer David Wheeler at one of the hacker sessions.

David suggested an approach in which we would keep the ./custom/clients/base/views/record/record.php which would define the button for every record. Then a new file that would enable us to include the javascript code behind the button click event in every module in SugarCRM that displays the record view.

This new file would be ./custom/clients/base/layouts/record/record.php.

In record.php we injected our custom layout, pm-record-logic, into the baseline record view. This pm-record-logic layout was the key to ensure that custom javascript code was guaranteed to be present for the modules record view and this javascript would be available on the click event of the new action button.

The final file that was created with the help from David (this was the most important piece for us) was the pm-record-logic.js file. David suggested we extend the initialize function , call the _super method and then bind our code to the click event for the button created above. The code snippet is:

pm-record-logic.js

initialize: function(options) {

this._super("initialize", arguments);

this.context.on('button:pm_record_reports:click', this.pmRecordReports, this);

},

We will now present the code in its entirety with instructions for other solution providers to accomplish the same thing:

The first file is record.php and lives in ./custom/clients/base/views/record/record.php

record.php

<?php 

require_once('clients/base/views/record/record.php');

foreach($viewdefs['base']['view']['record']['buttons'] as &$set){
if( $set['type'] == 'actiondropdown' && $set['name'] == 'main_dropdown'){
$set['buttons'][] = array(
'type' => 'rowaction',
'event' => 'button:pm_record_reports:click',
'name' => 'pm_record_reports',
'label' => 'PM Record Reports',
'acl_action' => 'view',
            );
    }
}

This file adds the action button to the action menu. The ‘name’ => ‘pm_record_reports’ will map to a file ./custom/clients/base/views/pm-record-logic/pm-record-logic.js with an initialize function that will set this buttons name to a click event function.

The next file is also named record.php and lives in ./custom/clients/base/layouts/record/record.php

record.php

<?php 
require_once('clients/base/layouts/record/record.php');

if(isset($viewdefs['base']['layout']['record']['components'])){
foreach($viewdefs['base']['layout']['record']['components'] as &$subArray){
if(isset($subArray['layout']['components'])){
foreach($subArray['layout']['components'] as &$subsubArray){
if(isset($subsubArray['layout']['components'])){
$subsubArray['layout']['components'][] = array(
'layout' => 'pm-record-logic',
                        );
                }
break;
            }
        }
break;
    }
}

What is key in this file is the ‘layout’ => ‘pm-record-logic’. Which allows us to inject our custom view into every record view.

Our first file is:

./custom/clients/base/layouts/pm-record-logic/pm-record-logic.php

pm-record-logic.php

<?php

$viewdefs['base']['layout']['pm-record-logic'] = array(
'type' => 'simple',
'components' => array(
array(
'view' => 'pm-record-logic',
            ),
        ),
    );


And our handle bars file ./custom/clients/base/views/pm-record-logic/pm-record-logic.hbs

pm-record-logic.hbs

<div id="pm-record-logic">

</div>

And finally our pm-record-logic.js file which makes the api call to Process Manager to retrieve all the processes for the given object:

./custom/clients/base/views/pm-record-logic/pm-record-logic.js

pm-record-logic.js

({
    className: 'pm-record-logic tcenter',
initialize: function(options) {
this._super("initialize", arguments);
this.context.on('button:pm_record_reports:click', this.pmRecordReports, this);
    },
pmRecordReports: function() {
var object_id = this.model.get('id');
var object_name = this.model.attributes._module;
app.api.call('GET', app.api.buildURL('PM_ProcessManager/' + object_id + '/record_reports/' + object_name), null, {
success: function(data) {
app.drawer.open({
                    layout:'pm-record-reports',
                    context:{
                        PM_Data: data
                    }
                });
            },
error: function(error) {
app.alert.show("server-error", {
                    level: 'error',
                    messages: 'ERR_GENERIC_SERVER_ERROR',
                    autoCLose: false
                });
app.error.handleHttpError(error);
            }
        });
    },
})

The remaining files used in this customization are the view and layouts for the actual data returned by Process Manager to be shown in the drawer.

What was key to this customization, and what we learned from the outstanding support from John and David, was the ability to be able to guarantee that our new action button click event function in javascript would be placed on the action menu for most modules (excluding Leads) and that we had confidence that the javascript functions on the click event would also be present.