Dashlets
Overview
Dashlets are special view-component plugins that render data from a context and make use of the Dashlet plugin. They are typically made up of a controller JavaScript file (.js) and at least one Handlebars template (.hbs).
Hierarchy Diagram
Sugar loads the dashlet view components in the following manner:
Note: The Sugar application's client type is "base". For more information on the various client types, please refer to the User Interface page.
Dashlet Views
The are three views when working with dashlets: Preview, Dashlet View, and Configuration View. The following sections discuss the differences between views.
Preview
The preview view is used when selecting dashlets to add to your homepage. Preview variables in the metadata will be assigned to the custom model variables.
'preview' => array(
'key1' => 'value1',
),
The values in the preview metadata can be retrieved using:
this.model.get("key1");
Dashlet View
The dashlet view will render the content for the dashlet. It will also contain the settings for editing, removing, and refreshing the dashlet.
Configuration View
The configuration view is displayed when a user clicks the 'edit' option on the dashlet frame's drop-down menu. Config variables in the metadata will be assigned to the custom model variables
'config' => array(
//key value pairs of attributes
'key1' => 'value1',
),
The values in the config metadata can be retrieved using:
this.model.get("key1");
Dashlet Example
The RSS feed dashlet, located in ./clients/base/views/rssfeed/
, handles the display of RSS feeds to the user. The sections below outline the various files that render this dashlet.
Metadata
The Dashlet view contains the 'dashlets' metadata:
Parameters | Type | Required | Description |
label | String | yes | The name of the dashlet |
description | String | no | A description of the dashlet |
config | Object | yes | Pre-populated variables in the configuration view Note: Config variables in the metadata are assigned to the custom model variables. |
preview | Object | yes | Pre-populated variables in the preview |
filter | Object | no | Filter for display |
The RSS feed dashlets metadata is located in:
./clients/base/views/rssfeed/rssfeed.php
<?php
/*
* Your installation or use of this SugarCRM file is subject to the applicable
* terms available at
* http://support.sugarcrm.com/Resources/Master_Subscription_Agreements/.
* If you do not agree to all of the applicable terms or do not have the
* authority to bind the entity as an authorized representative, then do not
* install or use this SugarCRM file.
*
* Copyright (C) SugarCRM Inc. All rights reserved.
*/
$viewdefs['base']['view']['rssfeed'] = array(
'dashlets' => array(
array(
'label' => 'LBL_RSS_FEED_DASHLET',
'description' => 'LBL_RSS_FEED_DASHLET_DESCRIPTION',
'config' => array(
'limit' => 5,
'auto_refresh' => 0,
),
'preview' => array(
'limit' => 5,
'auto_refresh' => 0,
'feed_url' => 'http://blog.sugarcrm.com/feed/',
),
),
),
'panels' => array(
array(
'name' => 'panel_body',
'columns' => 2,
'labelsOnTop' => true,
'placeholders' => true,
'fields' => array(
array(
'name' => 'feed_url',
'label' => 'LBL_RSS_FEED_URL',
'type' => 'text',
'span' => 12,
'required' => true,
),
array(
'name' => 'limit',
'label' => 'LBL_RSS_FEED_ENTRIES_COUNT',
'type' => 'enum',
'options' => 'tasks_limit_options',
),
array(
'name' => 'auto_refresh',
'label' => 'LBL_DASHLET_REFRESH_LABEL',
'type' => 'enum',
'options' => 'sugar7_dashlet_reports_auto_refresh_options',
),
),
),
),
);
Controller
The rssfeed.js
controller file, shown below, contains the JavaScript to render the news articles on the dashlet. The Dashlet view must include 'Dashlet' plugin and can override initDashlet to add additional custom process while it is initializing.
./clients/base/views/rssfeed/rssfeed.js
/*
* Your installation or use of this SugarCRM file is subject to the applicable
* terms available at
* http://support.sugarcrm.com/Resources/Master_Subscription_Agreements/.
* If you do not agree to all of the applicable terms or do not have the
* authority to bind the entity as an authorized representative, then do not
* install or use this SugarCRM file.
*
* Copyright (C) SugarCRM Inc. All rights reserved.
*/
/**
* RSS Feed dashlet consumes an RSS Feed URL and displays it's content as a list
* of entries.
*
* The following items are configurable.
*
* - {number} limit Limit imposed to the number of records pulled.
* - {number} refresh How often (minutes) should refresh the data collection.
*
* @class View.Views.Base.RssfeedView
* @alias SUGAR.App.view.views.BaseRssfeedView
* @extends View.View
*/
({
plugins: ['Dashlet'],
/**
* Default options used when none are supplied through metadata.
*
* Supported options:
* - timer: How often (minutes) should refresh the data collection.
* - limit: Limit imposed to the number of records pulled.
*
* @property {Object}
* @protected
*/
_defaultOptions: {
limit: 5,
auto_refresh: 0
},
/**
* @inheritdoc
*/
initialize: function(options) {
options.meta = options.meta || {};
this._super('initialize', [options]);
this.loadData(options.meta);
},
/**
* Init dashlet settings
*/
initDashlet: function() {
// We only need to handle this if we are NOT in the configure screen
if (!this.meta.config) {
var options = {};
var self = this;
var refreshRate;
// Get and set values for limits and refresh
options.limit = this.settings.get('limit') || this._defaultOptions.limit;
this.settings.set('limit', options.limit);
options.auto_refresh = this.settings.get('auto_refresh') || this._defaultOptions.auto_refresh;
this.settings.set('auto_refresh', options.auto_refresh);
// There is no default for this so there's no pointing in setting from it
options.feed_url = this.settings.get('feed_url');
// Set the refresh rate for setInterval so it can be checked ahead
// of time. 60000 is 1000 miliseconds times 60 seconds in a minute.
refreshRate = options.auto_refresh * 60000;
// Only set up the interval handler if there is a refreshRate higher
// than 0
if (refreshRate > 0) {
if (this.timerId) {
clearInterval(this.timerId);
}
this.timerId = setInterval(_.bind(function() {
if (self.context) {
self.context.resetLoadFlag();
self.loadData(options);
}
}, this), refreshRate);
}
}
// Validation handling for individual fields on the config
this.layout.before('dashletconfig:save', function() {
// Fields on the metadata
var fields = _.flatten(_.pluck(this.meta.panels, 'fields'));
// Grab all non-valid fields from the model
var notValid = _.filter(fields, function(field) {
return field.required && !this.dashModel.get(field.name);
}, this);
// If there no invalid fields we are good to go
if (notValid.length === 0) {
return true;
}
// Otherwise handle notification of invalidation
_.each(notValid, function(field) {
var fieldOnView = _.find(this.fields, function(comp, cid) {
return comp.name === field.name;
});
fieldOnView.model.trigger('error:validation:' + field.name, {required: true});
}, this);
// False return tells the drawer that it shouldn't close
return false;
}, this);
},
/**
* Handles the response of the feed consumption request and sets data from
* the result
*
* @param {Object} data Response from the rssfeed API call
*/
handleFeed: function (data) {
if (this.disposed) {
return;
}
// Load up the template
_.extend(this, data);
this.render();
},
/**
* Loads an RSS feed from the RSS Feed endpoint.
*
* @param {Object} options The metadata that drives this request
*/
loadData: function(options) {
if (options && options.feed_url) {
var callbacks = {success: _.bind(this.handleFeed, this), error: _.bind(this.handleFeed, this)},
limit = options.limit || this._defaultOptions.limit,
params = {feed_url: options.feed_url, limit: limit},
apiUrl = app.api.buildURL('rssfeed', 'read', '', params);
app.api.call('read', apiUrl, {}, callbacks);
}
},
/**
* @inheritdoc
*
* New model related properties are injected into each model:
*
* - {Boolean} overdue True if record is prior to now.
*/
_renderHtml: function() {
if (this.meta.config) {
this._super('_renderHtml');
return;
}
this._super('_renderHtml');
}
})
Workflow
When triggered, the following procedure will render the view area:
Retrieving Data
Use the following commands to retrieve the corresponding data:
Data Location | Element | Command |
Main pane | Record View | this.model |
Record View | this.context.parent.get("model") |
|
List View | this.context.parent.get("collection") |
|
Metadata | this.dashletConfig['metadata_key'] |
|
Module vardefs | app.metadata.getModule("ModuleName") |
|
Remote data | Bean | new app.data.createBean("Module") new app.data.createBeanCollection("Module") |
RestAPI | app.api.call(method, url, data, callbacks, options) |
|
Ajax Call | $.ajax() |
|
User inputs | this.settings.get("custom_key") |
Handlebar Template
The rssfeed.hbs
template file defines the content of the view. This view is used for rendering the markup rendering in the dashlet content.
./clients/base/views/rssfeed/rssfeed.hbs
{{!--
/*
* Your installation or use of this SugarCRM file is subject to the applicable
* terms available at
* http://support.sugarcrm.com/Resources/Master_Subscription_Agreements/.
* If you do not agree to all of the applicable terms or do not have the
* authority to bind the entity as an authorized representative, then do not
* install or use this SugarCRM file.
*
* Copyright (C) SugarCRM Inc. All rights reserved.
*/
--}}
{{#if feed}}
<div class="rss-feed">
<h4>
{{#if feed.link}}<a href="{{feed.link}}">{{/if}}
{{feed.title}}
{{#if feed.link}}</a>{{/if}}
</h4>
<ul>
{{#each feed.entries}}
<li class="news-article">
<a href="{{link}}">{{title}}</a>
{{#if author}} - {{str "LBL_RSS_FEED_AUTHOR"}} {{author}}{{/if}}
</li>
{{/each}}
</ul>
</div>
{{else}}
<div class="block-footer">
{{#if errorThrown}}
{{str "LBL_NO_DATA_AVAILABLE"}}
{{else}}
{{loading 'LBL_ALERT_TITLE_LOADING'}}
{{/if}}
</div>
{{/if}}