Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CPS-472: Add My Activities Feed dashlet #754

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions CRM/Civicase/Hook/PageRun/AddCivicaseDashlets.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

use Civi\Angular\AngularLoader;

/**
* Loads Civicase Angular dashlets when viewing the dashboard page.
*/
class CRM_Civicase_Hook_PageRun_AddCivicaseDashlets {

/**
* Runs the hook.
*
* @param object $page
* Page Object.
*/
public function run($page) {
if (!$this->shouldRun($page)) {
return;
}

CRM_Core_Resources::singleton()
->addScriptFile('uk.co.compucorp.civicase', 'packages/moment.min.js');

$loader = new AngularLoader();
$loader->setModules(['civicase']);
$loader->load();
}

/**
* Determines if the hook should run.
*
* @param object $page
* Page Object.
*
* @return bool
* True when viewing the dashboard page.
*/
private function shouldRun($page) {
return get_class($page) === CRM_Contact_Page_DashBoard::class;
}

}
31 changes: 31 additions & 0 deletions CRM/Civicase/Upgrader/Steps/Step0015.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

/**
* Adds the My Activities Feed dashlet to the dashboard.
*/
class CRM_Civicase_Upgrader_Steps_Step0015 {

/**
* Runs the upgrader changes.
*
* @return bool
* Return TRUE when the upgrader runs successfully.
*/
public function apply() {
civicrm_api3('Dashboard', 'create', [
'name' => 'myactivitiesfeed',
'label' => 'My Activities Feed',
'url' => '',
'fullscreen_url' => '',
'permission' => 'access all cases and activities,access my cases and activities',
'permission_operator' => 'OR',
'is_active' => '1',
'is_reserved' => '1',
'cache_minutes' => '7200',
'directive' => 'civicase-my-activities-feed-dashlet',
]);

return TRUE;
}

}
20 changes: 14 additions & 6 deletions ang/civicase/activity/feed/directives/activity-feed.directive.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
canSelectCaseTypeCategory: '=',
caseTypeId: '=',
refreshCase: '=?refreshCallback',
skipUrlParamatersBinding: '<',
hideQuickNavWhenDetailsIsVisible: '='
}
};
Expand Down Expand Up @@ -79,6 +80,11 @@
var pageNum = { down: 0, up: 0 };
var activitySets = $scope.caseTypeId &&
CaseType.getById($scope.caseTypeId).definition.activitySets;
var DEFAULT_DISPLAY_OPTIONS = angular.extend({}, {
followup_nested: true,
overdue_first: true,
include_case: true
}, $scope.params.displayOptions || {});

$scope.filters = {};
$scope.isMonthNavVisible = true;
Expand All @@ -100,7 +106,13 @@

(function init () {
applyFiltersFromBindings();
bindRouteParamsToScope();

if ($scope.skipUrlParamatersBinding) {
$scope.displayOptions = DEFAULT_DISPLAY_OPTIONS;
} else {
bindRouteParamsToScope();
}

initiateWatchersAndEvents();
}());

Expand Down Expand Up @@ -226,11 +238,7 @@
$scope.$bindToRoute({
expr: 'displayOptions',
param: 'ado',
default: angular.extend({}, {
followup_nested: true,
overdue_first: true,
include_case: true
}, $scope.params.displayOptions || {})
default: DEFAULT_DISPLAY_OPTIONS
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div id="bootstrap-theme">
<div
civicase-activity-feed="{ filters: filters }"
hide-quick-nav-when-details-is-visible="true"
show-bulk-actions="true"
skip-url-paramaters-binding="true"
></div>
</div>
35 changes: 35 additions & 0 deletions ang/civicase/dashlets/my-activities-feed-dashlet.directive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
(function (_, angular) {
var module = angular.module('civicase');

module.directive('civicaseMyActivitiesFeedDashlet', function () {
return {
controller: 'civicaseMyActivitiesFeedDashletController',
templateUrl: '~/civicase/dashlets/my-activities-feed-dashlet.directive.html'
};
});

module.controller('civicaseMyActivitiesFeedDashletController', civicaseMyActivitiesFeedDashletController);

/**
* My Activities Feed Dashlet controller.
*
* @param {object} $scope Scope Object reference.
* @param {object} ActivityStatus Activity Status service.
* @param {object} Contact Contact service.
*/
function civicaseMyActivitiesFeedDashletController ($scope, ActivityStatus, Contact) {
(function init () {
var INCOMPLETE_ACTIVITY_STATUS_CATEGORY = '0';
var incompletedActivityStatusIds = _.chain(ActivityStatus.getAll())
.filter({ filter: INCOMPLETE_ACTIVITY_STATUS_CATEGORY })
.map('value')
.value();

$scope.filters = {
$contact_id: Contact.getCurrentContactID(),
'@involvingContact': 'myActivities',
status_id: incompletedActivityStatusIds
};
})();
}
})(CRM._, angular);
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
color: '#d9534f',
name: 'Unread',
grouping: 'communication',
is_active: '1'
is_active: '1',
weight: '9',
filter: '0'
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
showFullContactNameOnActivityFeed = _showFullContactNameOnActivityFeed_;

$scope = $rootScope.$new();
$scope.caseTypeId = '1';
$scope.filters = {};
$scope.displayOptions = {};
$scope.params = {
displayOptions: 1
};
$scope.$bindToRoute = jasmine.createSpy('$bindToRoute');
civicaseCrmApi = _civicaseCrmApi_;
}));
Expand All @@ -38,6 +44,92 @@
});
});

describe('binding URL parameters to scope', () => {
describe('when we do not skip URL parameters binding', () => {
beforeEach(() => {
initController();
});

it('binds the current activity ID parameter', () => {
expect($scope.$bindToRoute).toHaveBeenCalledWith(jasmine.objectContaining({
param: 'aid',
expr: 'aid'
}));
});

it('binds the activity filters parameters', () => {
expect($scope.$bindToRoute).toHaveBeenCalledWith(jasmine.objectContaining({
param: 'af',
expr: 'filters'
}));
});

it('binds the activity display option parameters', () => {
expect($scope.$bindToRoute).toHaveBeenCalledWith(jasmine.objectContaining({
param: 'ado',
expr: 'displayOptions'
}));
});

describe('when passing display options', () => {
beforeEach(() => {
$scope.params.displayOptions = { custom_display_option: true };

initController();
});

it('adds default parameters to the display options URL binding', () => {
expect($scope.$bindToRoute).toHaveBeenCalledWith(jasmine.objectContaining({
param: 'ado',
expr: 'displayOptions',
default: jasmine.objectContaining({
followup_nested: true,
overdue_first: true,
include_case: true
})
}));
});

it('uses the values passed as defaults for the display options URL binding', () => {
expect($scope.$bindToRoute).toHaveBeenCalledWith(jasmine.objectContaining({
param: 'ado',
expr: 'displayOptions',
default: jasmine.objectContaining({
custom_display_option: true
})
}));
});
});
});

describe('when we skip the URL paramaters binding', () => {
beforeEach(() => {
$scope.skipUrlParamatersBinding = true;
$scope.params.displayOptions = { custom_display_option: true };

initController();
});

it('does not bind the URL parameters to the scope', () => {
expect($scope.$bindToRoute).not.toHaveBeenCalled();
});

it('sets the default values for the display options', () => {
expect($scope.displayOptions).toEqual(jasmine.objectContaining({
followup_nested: true,
overdue_first: true,
include_case: true
}));
});

it('includes the default values passed to the display options', () => {
expect($scope.displayOptions).toEqual(jasmine.objectContaining({
custom_display_option: true
}));
});
});
});

describe('loadActivities', () => {
beforeEach(() => {
activitiesInCurrentPage = [];
Expand Down Expand Up @@ -389,13 +481,6 @@
* Initializes the activity feed controller.
*/
function initController () {
$scope.caseTypeId = '1';
$scope.filters = {};
$scope.displayOptions = {};
$scope.params = {
displayOptions: 1
};

$controller('civicaseActivityFeedController', {
$scope: $scope
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
((_) => {
describe('civicaseMyActivitiesFeedDashlet', () => {
let $controller, $rootScope, $scope, Contact;

beforeEach(module('civicase', 'civicase.data'));

beforeEach(inject((_$controller_, _$rootScope_, _Contact_) => {
$controller = _$controller_;
$rootScope = _$rootScope_;
Contact = _Contact_;

$scope = $rootScope.$new();
}));

describe('activity filters', () => {
const INCOMPLETE_ACTIVITY_STATUSES = [
{ value: '1', label: 'Scheduled' },
{ value: '4', label: 'Left Message' },
{ value: '7', label: 'Available' },
{ value: '9', label: 'Unread' },
{ value: '10', label: 'Draft' }
];

beforeEach(() => {
initController();
});

it('filters activities by the current logged in user ID', () => {
expect($scope.filters.$contact_id).toEqual(Contact.getCurrentContactID());
});

it('filters activities assigned to the current logged in user', () => {
expect($scope.filters['@involvingContact']).toEqual('myActivities');
});

it('filters activities that have not been completed', () => {
expect($scope.filters.status_id)
.toEqual(_.map(INCOMPLETE_ACTIVITY_STATUSES, 'value'));
});
});

/**
* Initializes the directive's controller.
*/
function initController () {
$controller('civicaseMyActivitiesFeedDashletController', {
$scope: $scope
});
}
});
})(CRM._);
Loading