CRM-17663 - Configurable cache time per dashlet & auto-refresh
authorColeman Watts <coleman@civicrm.org>
Tue, 9 Aug 2016 22:42:56 +0000 (18:42 -0400)
committerColeman Watts <coleman@civicrm.org>
Fri, 12 Aug 2016 03:32:35 +0000 (23:32 -0400)
15 files changed:
CRM/Admin/Form/Setting/Miscellaneous.php
CRM/Core/BAO/Dashboard.php
CRM/Core/Config/MagicMerge.php
CRM/Report/BAO/ReportInstance.php
CRM/Report/Form/Instance.php
CRM/Upgrade/Incremental/php/FourSeven.php
api/v3/examples/Setting/GetFields.php
js/jquery/jquery.dashboard.js
settings/Core.setting.php
templates/CRM/Admin/Form/Setting/Miscellaneous.tpl
templates/CRM/Report/Form/Tabs/Instance.tpl
templates/CRM/Report/Form/Tabs/Settings.hlp
templates/CRM/common/dashboard.tpl
xml/schema/Core/Dashboard.xml
xml/templates/civicrm_navigation.tpl

index 68f68d15a2f2a4ad24405064f0b5ce981a9b32d4..762d8b346807d011af75df47d39c5fe98bca15fe 100644 (file)
@@ -39,7 +39,6 @@ class CRM_Admin_Form_Setting_Miscellaneous extends CRM_Admin_Form_Setting {
   protected $_settings = array(
     'max_attachments' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
     'contact_undelete' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
-    'dashboardCacheTimeout' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
     'empoweredBy' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
     'logging' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
     'maxFileSize' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
@@ -89,7 +88,6 @@ class CRM_Admin_Form_Setting_Miscellaneous extends CRM_Admin_Form_Setting {
 
     parent::buildQuickForm();
     $this->addRule('checksum_timeout', ts('Value should be a positive number'), 'positiveInteger');
-    $this->addRule('dashboardCacheTimeout', ts('Value should be a positive number'), 'positiveInteger');
   }
 
   /**
index a763c185645cc2ecbb837220a7a189c6f0b1fa40..f0f4c03f8d02614911678c75bcbfd205440487e0 100644 (file)
@@ -118,6 +118,7 @@ class CRM_Core_BAO_Dashboard extends CRM_Core_DAO_Dashboard {
         'dashboard_id.label',
         'dashboard_id.url',
         'dashboard_id.fullscreen_url',
+        'dashboard_id.cache_minutes',
         'dashboard_id.permission',
         'dashboard_id.permission_operator',
       ),
@@ -132,6 +133,7 @@ class CRM_Core_BAO_Dashboard extends CRM_Core_DAO_Dashboard {
           'name' => $item['dashboard_id.name'],
           'label' => $item['dashboard_id.label'],
           'url' => $item['dashboard_id.url'],
+          'cache_minutes' => $item['dashboard_id.cache_minutes'],
           'fullscreen_url' => $item['dashboard_id.fullscreen_url'],
         );
       }
@@ -159,6 +161,7 @@ class CRM_Core_BAO_Dashboard extends CRM_Core_DAO_Dashboard {
         'name' => $item['name'],
         'title' => $item['label'],
         'url' => self::parseUrl($item['url']),
+        'cacheMinutes' => $item['cache_minutes'],
         'fullscreenUrl' => self::parseUrl($item['fullscreen_url']),
       );
     }
@@ -212,6 +215,7 @@ class CRM_Core_BAO_Dashboard extends CRM_Core_DAO_Dashboard {
             'column_no' => $values['column_no'],
             'name' => $dashlet['name'],
             'label' => $dashlet['label'],
+            'cache_minutes' => $dashlet['cache_minutes'],
             'url' => $dashlet['url'],
             'fullscreen_url' => $dashlet['fullscreen_url'],
           );
index b1b84ab86814059fc9f488b1a575ab0727a98dab..37c15ef5553d0df614b111c6f25aeefe3d966fe5 100644 (file)
@@ -118,7 +118,6 @@ class CRM_Core_Config_MagicMerge {
       'backtrace' => array('setting'),
       'contact_default_language' => array('setting'),
       'countryLimit' => array('setting'),
-      'dashboardCacheTimeout' => array('setting'),
       'dateInputFormat' => array('setting'),
       'dateformatDatetime' => array('setting'),
       'dateformatFull' => array('setting'),
index 16680501f0d4350b8cd31a9bb514a6b957e24028..fcb3a7ff9ba569eedde0ef75d1b797dd81162a08 100644 (file)
@@ -215,9 +215,12 @@ class CRM_Report_BAO_ReportInstance extends CRM_Report_DAO_ReportInstance {
         $section = 1;
         $chart = "&charts=" . $params['charts'];
       }
-      if (!empty($params['row_count'])) {
+      if (!empty($params['row_count']) && CRM_Utils_Rule::positiveInteger($params['row_count'])) {
         $limitResult = '&rowCount=' . $params['row_count'];
       }
+      if (!empty($params['cache_minutes']) && CRM_Utils_Rule::positiveInteger($params['cache_minutes'])) {
+        $dashletParams['cache_minutes'] = $params['cache_minutes'];
+      }
       $dashletParams['name'] = "report/{$instance->id}";
       $dashletParams['url'] = "civicrm/report/instance/{$instance->id}?reset=1&section={$section}{$chart}&context=dashlet" . $limitResult;
       $dashletParams['fullscreen_url'] = "civicrm/report/instance/{$instance->id}?reset=1&section={$section}{$chart}&context=dashletFullscreen" . $limitResult;
index b57391871b9b4ce44bcd285fcd42ad3d84baa4af..22cf52d7c3fba9587d7b360f9016b301aeeab01a 100644 (file)
@@ -82,13 +82,10 @@ class CRM_Report_Form_Instance {
       $attributes['email_subject']
     );
 
-    $form->add('text',
+    $form->add('number',
       'row_count',
       ts('Limit Dashboard Results'),
-      array(
-        'maxlength' => 64,
-        'size' => 5,
-      )
+      array('class' => 'four', 'min' => 1)
     );
 
     $form->add('textarea',
@@ -112,8 +109,8 @@ class CRM_Report_Form_Instance {
       'criteria' => ts('Show Criteria'),
     ));
 
-    $form->addElement('checkbox', 'addToDashboard', ts('Available for Dashboard?'), NULL,
-      array('onclick' => "return showHideByValue('addToDashboard','','limit_result','table-row','radio',false);"));
+    $form->addElement('checkbox', 'addToDashboard', ts('Available for Dashboard?'));
+    $form->add('number', 'cache_minutes', ts('Cache dashlet for'), array('class' => 'four', 'min' => 1));
     $form->addElement('checkbox', 'add_to_my_reports', ts('Add to My Reports?'), NULL);
 
     $form->addElement('checkbox', 'is_reserved', ts('Reserved Report?'));
@@ -263,6 +260,10 @@ class CRM_Report_Form_Instance {
       $defaults['view_mode'] = 'criteria';
     }
 
+    if (empty($defaults['cache_minutes'])) {
+      $defaults['cache_minutes'] = '60';
+    }
+
     if ($instanceID) {
       // this is already retrieved via Form.php
       $defaults['description'] = CRM_Utils_Array::value('description', $defaults);
index 0e523bf5f174d2ea0d787f873c072a38670ded80..9988e9c6d696a245578e5fd3070d32eeb2c566ce 100644 (file)
@@ -760,6 +760,13 @@ FROM `civicrm_dashboard_contact` JOIN `civicrm_contact` WHERE civicrm_dashboard_
     CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard', 'weight');
 
     CRM_Core_DAO::executeQuery('UPDATE civicrm_dashboard SET url = REPLACE(url, "&snippet=5", ""), fullscreen_url = REPLACE(fullscreen_url, "&snippet=5", "")');
+
+    if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_dashboard', 'cache_minutes')) {
+      CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_dashboard ADD COLUMN cache_minutes int unsigned NOT NULL DEFAULT 60 COMMENT "Number of minutes to cache dashlet content in browser localStorage."');
+    }
+
+    CRM_Core_DAO::executeQuery('UPDATE civicrm_dashboard SET cache_minutes = 1440 WHERE name = "blog"');
+    CRM_Core_DAO::executeQuery('UPDATE civicrm_dashboard SET cache_minutes = 7200 WHERE name IN ("activity","getting-started")');
     return TRUE;
   }
 
index 4d3549586d95651a7fa3c764046c789015f7fd40..df623eb6ceccbce7196ca877577623651e759c72 100644 (file)
@@ -620,27 +620,6 @@ function setting_getfields_expectedresult() {
         'description' => '',
         'help_text' => '',
       ),
-      'dashboardCacheTimeout' => array(
-        'group_name' => 'CiviCRM Preferences',
-        'group' => 'core',
-        'name' => 'dashboardCacheTimeout',
-        'prefetch' => 1,
-        'config_only' => 1,
-        'type' => 'Integer',
-        'quick_form_type' => 'Element',
-        'html_attributes' => array(
-          'size' => 3,
-          'maxlength' => 5,
-        ),
-        'html_type' => 'Text',
-        'default' => '',
-        'add' => '4.3',
-        'title' => 'Dashboard cache timeout',
-        'is_domain' => 1,
-        'is_contact' => 0,
-        'description' => '',
-        'help_text' => '',
-      ),
       'checksumTimeout' => array(
         'group_name' => 'CiviCRM Preferences',
         'group' => 'core',
index 3561922369a15d4ffeb32e9acec27f65499fd7c7..394635d3618260770817cc7a4f01479f4d24a63f 100644 (file)
         $("#empty-message").show( );
     }
 
+    // Cache dashlet info in localStorage
     function saveLocalCache() {
       localCache = {};
       $.each(dashboard.widgets, function(id, widget) {
         localCache[id] = {
           content: widget.content,
-          expires: widget.expires,
+          lastLoaded: widget.lastLoaded,
           minimized: widget.minimized
         };
       });
       dashboard.saveColumns();
       dashboard.ready = true;
       invokeCallback(opts.callbacks.ready, dashboard);
+
+      // Auto-refresh widgets when content is stale
+      window.setInterval(function() {
+        if (!document.hasFocus || document.hasFocus()) {
+          $.each(dashboard.widgets, function (i, widget) {
+            if (!widget.cacheIsFresh()) {
+              widget.reloadContent();
+            }
+          });
+        }
+      }, 5000);
     }
 
     // Callback for when any list has changed (and the user has finished resorting).
         // If minimized, we'll reload later
         if (widget.minimized) {
           widget.contentLoaded = false;
-          widget.expires = 0;
+          widget.lastLoaded = 0;
         } else {
           CRM.loadPage(widget.url, {target: widget.contentElement});
         }
         );
       };
 
+      widget.cacheIsFresh = function() {
+        return (((widget.cacheMinutes * 60000 + widget.lastLoaded) > $.now()) && widget.content);
+      };
+
       /**
        * Public properties of widget.
        */
        */
 
       function loadContent() {
-        var loadFromCache = (widget.expires > $.now() && widget.content);
+        var loadFromCache = widget.cacheIsFresh();
         if (loadFromCache) {
           widget.contentElement.html(widget.content).trigger('crmLoad', widget);
         }
           if ($(event.target).is(widget.contentElement)) {
             widget.content = data.content;
             // Cache for one day
-            widget.expires = $.now() + 86400000;
+            widget.lastLoaded = $.now();
             saveLocalCache();
             invokeCallback(opts.widgetCallbacks.get, widget);
           }
   // Public static properties of dashboard.  Default settings.
   $.fn.dashboard.defaults = {
     columns: 2,
-    emptyPlaceholderInner: ts('There are no dashlets in this column of your dashboard.'),
+    emptyPlaceholderInner: '',
     throbberMarkup: '',
     animationSpeed: 200,
     callbacks: {},
     defaults: {
       minimized: false,
       content: null,
-      expires: 0,
+      lastLoaded: 0,
       settings: false
-      // url, fullscreenUrl, title, name
+      // id, url, fullscreenUrl, title, name, cacheMinutes
     }
   };
 })(jQuery);
index f8fa1904bff9a1ca06c23ea02cfff89e3f1c8d61..6430d873b8c5e35f1251500117d2b8359bfc7ac8 100644 (file)
@@ -497,25 +497,6 @@ return array(
     'description' => NULL,
     'help_text' => NULL,
   ),
-  'dashboardCacheTimeout' => array(
-    'group_name' => 'CiviCRM Preferences',
-    'group' => 'core',
-    'name' => 'dashboardCacheTimeout',
-    'type' => 'Integer',
-    'quick_form_type' => 'Element',
-    'html_attributes' => array(
-      'size' => 3,
-      'maxlength' => 5,
-    ),
-    'html_type' => 'Text',
-    'default' => NULL,
-    'add' => '4.3',
-    'title' => 'Dashboard cache timeout',
-    'is_domain' => 1,
-    'is_contact' => 0,
-    'description' => NULL,
-    'help_text' => NULL,
-  ),
   'checksum_timeout' => array(
     'group_name' => 'CiviCRM Preferences',
     'group' => 'core',
index 5d5c18704989f6b9e91ea6ccefd6572837192b7b..32125f896663a7ffd3040e4bad4858b3a2b1cba7 100644 (file)
 *}
 <div class="crm-block crm-form-block crm-miscellaneous-form-block">
   <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
-    <table class="form-layout">
-        <tr class="crm-miscellaneous-form-block-dashboardCacheTimeout">
-            <td class="label">{$form.dashboardCacheTimeout.label}</td>
-            <td>{$form.dashboardCacheTimeout.html}<br />
-                <span class="description">{ts}The number of minutes to cache dashlet content on dashboard.{/ts}</span></td>
-        </tr>
-    </table>
 
     <table class="form-layout">
         <tr class="crm-miscellaneous-form-block-checksum_timeout">
index ca7db8c37e4134154aaf176593697407e126028f..b269d618b0323b69682ad01692319c8adf1f673b 100644 (file)
         <span class="description">{ts}Users with appropriate permissions can add this report to their dashboard.{/ts}</span>
       </td>
     </tr>
-    <tr id ="limit_result" class="crm-report-instanceForm-form-block-limitUser">
+    <tr class="crm-report-instanceForm-form-block-limitUser">
       <td class="report-label">{$form.row_count.label} {help id="id-dash_limit" file="CRM/Report/Form/Tabs/Settings.hlp"}</td>
-      <td>{$form.row_count.html}</td>
+      <td>{$form.row_count.html} {ts}rows{/ts}</td>
+    </tr>
+    <tr class="crm-report-instanceForm-form-block-cache_minutes">
+      <td class="report-label">{$form.cache_minutes.label} {help id="cache_minutes" file="CRM/Report/Form/Tabs/Settings.hlp"}</td>
+      <td>{$form.cache_minutes.html} {ts}minutes{/ts}</td>
     </tr>
   </table>
 </div>
     field_type          ="radio"
     invert              = 0
 }
-{include file="CRM/common/showHideByFieldValue.tpl"
-    trigger_field_id    ="addToDashboard"
-    trigger_value       =""
-    target_element_id   ="limit_result"
-    target_element_type ="table-row"
-    field_type          ="radio"
-    invert              = 0
-}
-
+{literal}
+<script type="text/javascript">
+  CRM.$(function($) {
+    function showHideDashletControls() {
+      $('.crm-report-instanceForm-form-block-limitUser, .crm-report-instanceForm-form-block-cache_minutes').toggle($(this).is(':checked'));
+    }
+    $('#addToDashboard').each(showHideDashletControls).change(showHideDashletControls);
+  });
+</script>
+{/literal}
 {if $is_navigation}
   <script type="text/javascript">
     document.getElementById('is_navigation').checked = true;
index 6c85a44ff4812300542f24ef2f0898f3fecd682d..55465e73ea2c9a4143a0c93bcdd820c389be1905 100644 (file)
   {ts}The default number of rows per page for most reports is 50. However, this may be too many for a report which is included in the 'Home Dashboard'. You can reduce the number of rows included in each page when the report is part of the Dashboard by entering the desired row count here. Users will still be able to navigate through the full report using a pager.{/ts}
 {/htxt}
 
+{htxt id="cache_minutes-title"}
+  {ts}Dashboard Caching{/ts}
+{/htxt}
+{htxt id="cache_minutes"}
+  {ts}How often should the contents of this dashlet be automatically refreshed? Users can manually reload by clicking the refresh button on their dashboards.{/ts}
+{/htxt}
+
 {htxt id="id-is_reserved-title"}
   {ts}Reserved{/ts}
 {/htxt}
index f2b15cd9cf434a4c83e6418691f681e90ec82e21..ee61aacd8b1cad80e9f413ed7a06f3dfe2aee838 100644 (file)
 CRM.$(function($) {
   // The set of options we can use to initialize jQuery.dashboard().
   var options = {
-    // Optional. Defaults to 3.  You'll need to change the width of columns in CSS too.
-    columns: 2,
-
-    // Set this to a link to your server-side script that adds widgets to the dashboard.
-    // The server will need to choose a column to add it to, and change the user's settings
-    // stored server-side.
-    // Required.
-    emptyPlaceholderInner: '',
 
     widgetsByColumn: {/literal}{$contactDashlets|@json_encode}{literal},
 
index 7644c135be47ffac4a174c8ec1d9608c0d6ca001..41ed111374447b1832f6041175f96f27f025dc00 100644 (file)
     <add>3.1</add>
     <drop>4.7</drop>
   </field>
+  <field>
+    <name>cache_minutes</name>
+    <type>int unsigned</type>
+    <title>Cache Minutes</title>
+    <comment>Number of minutes to cache dashlet content in browser localStorage.</comment>
+    <default>60</default>
+    <required>true</required>
+    <add>4.7</add>
+  </field>
   <field>
     <name>created_date</name>
     <type>datetime</type>
index 1d09f34c69b1b22f58e70b0b41fec23cd7c6d2b2..fcb2ceb36348cb16693c60c65ebc88dbf4e4ab6c 100644 (file)
@@ -37,15 +37,15 @@ INSERT INTO civicrm_mail_settings (domain_id, name, is_default, domain) VALUES (
 -- activity and case dashlets
 
 INSERT INTO `civicrm_dashboard`
-    ( `domain_id`, `name`, `label`, `url`, `permission`, `permission_operator`, `is_active`, `fullscreen_url`, `is_reserved`)
+    ( `domain_id`, `name`, `label`, `url`, `permission`, `permission_operator`, `is_active`, `fullscreen_url`, `is_reserved`, `cache_minutes`)
     VALUES
-    ( @domainID, 'blog', '{ts escape="sql"}CiviCRM News{/ts}', 'civicrm/dashlet/blog?reset=1', 'access CiviCRM', NULL, 1, 'civicrm/dashlet/blog?reset=1&context=dashletFullscreen', 1),
-    ( @domainID, 'getting-started', '{ts escape="sql"}CiviCRM Resources{/ts}', 'civicrm/dashlet/getting-started?reset=1', 'access CiviCRM', NULL, 1, 'civicrm/dashlet/getting-started?reset=1&context=dashletFullscreen', 1),
+    ( @domainID, 'blog', '{ts escape="sql"}CiviCRM News{/ts}', 'civicrm/dashlet/blog?reset=1', 'access CiviCRM', NULL, 1, 'civicrm/dashlet/blog?reset=1&context=dashletFullscreen', 1, 1440),
+    ( @domainID, 'getting-started', '{ts escape="sql"}CiviCRM Resources{/ts}', 'civicrm/dashlet/getting-started?reset=1', 'access CiviCRM', NULL, 1, 'civicrm/dashlet/getting-started?reset=1&context=dashletFullscreen', 1, 7200),
 
-    ( @domainID, 'activity', '{ts escape="sql"}Activities{/ts}', 'civicrm/dashlet/activity?reset=1', 'access CiviCRM', NULL, 1, 'civicrm/dashlet/activity?reset=1&context=dashletFullscreen', 1),
-    ( @domainID, 'myCases', '{ts escape="sql"}My Cases{/ts}', 'civicrm/dashlet/myCases?reset=1', 'access my cases and activities', NULL, 1, 'civicrm/dashlet/myCases?reset=1&context=dashletFullscreen', 1),
-    ( @domainID, 'allCases', '{ts escape="sql"}All Cases{/ts}', 'civicrm/dashlet/allCases?reset=1', 'access all cases and activities', NULL, 1, 'civicrm/dashlet/allCases?reset=1&context=dashletFullscreen', 1),
-    ( @domainID, 'casedashboard', '{ts escape="sql"}Case Dashboard Dashlet{/ts}', 'civicrm/dashlet/casedashboard?reset=1', 'access my cases and activities,access all cases and activities', 'OR', 1, 'civicrm/dashlet/casedashboard?reset=1&context=dashletFullscreen', 1);
+    ( @domainID, 'activity', '{ts escape="sql"}Activities{/ts}', 'civicrm/dashlet/activity?reset=1', 'access CiviCRM', NULL, 1, 'civicrm/dashlet/activity?reset=1&context=dashletFullscreen', 1, 7200),
+    ( @domainID, 'myCases', '{ts escape="sql"}My Cases{/ts}', 'civicrm/dashlet/myCases?reset=1', 'access my cases and activities', NULL, 1, 'civicrm/dashlet/myCases?reset=1&context=dashletFullscreen', 1, 60),
+    ( @domainID, 'allCases', '{ts escape="sql"}All Cases{/ts}', 'civicrm/dashlet/allCases?reset=1', 'access all cases and activities', NULL, 1, 'civicrm/dashlet/allCases?reset=1&context=dashletFullscreen', 1, 60),
+    ( @domainID, 'casedashboard', '{ts escape="sql"}Case Dashboard Dashlet{/ts}', 'civicrm/dashlet/casedashboard?reset=1', 'access my cases and activities,access all cases and activities', 'OR', 1, 'civicrm/dashlet/casedashboard?reset=1&context=dashletFullscreen', 1, 60);
 
 -- event badge
 INSERT INTO civicrm_print_label (title, name, description, label_format_name, label_type_id, is_default, is_reserved, is_active, data)