Merge pull request #9611 from edx/dan-f/add-team-page-viewed-events
Add page viewed events to teams app.
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
define([
|
||||
'jquery',
|
||||
'backbone',
|
||||
'logger',
|
||||
'common/js/spec_helpers/ajax_helpers',
|
||||
'common/js/spec_helpers/spec_helpers',
|
||||
'teams/js/views/teams_tab',
|
||||
'teams/js/spec_helpers/team_spec_helpers'
|
||||
], function ($, Backbone, AjaxHelpers, TeamsTabView, TeamSpecHelpers) {
|
||||
], function ($, Backbone, Logger, AjaxHelpers, SpecHelpers, TeamsTabView, TeamSpecHelpers) {
|
||||
'use strict';
|
||||
|
||||
describe('TeamsTab', function () {
|
||||
@@ -34,14 +36,34 @@ define([
|
||||
return teamsTabView;
|
||||
};
|
||||
|
||||
/**
|
||||
* Filters out all team events from a list of requests.
|
||||
*/
|
||||
var removeTeamEvents = function (requests) {
|
||||
return requests.filter(function (request) {
|
||||
if (request.requestBody && request.requestBody.startsWith('event_type=edx.team')) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
setFixtures('<div class="teams-content"></div>');
|
||||
spyOn($.fn, 'focus');
|
||||
spyOn(Logger, 'log');
|
||||
});
|
||||
|
||||
afterEach(Backbone.history.stop);
|
||||
|
||||
describe('Navigation', function () {
|
||||
it('does not interfere with anchor links to #content', function () {
|
||||
var teamsTabView = createTeamsTabView();
|
||||
teamsTabView.router.navigate('#content', {trigger: true});
|
||||
expect(teamsTabView.$('.warning')).toHaveClass('is-hidden');
|
||||
});
|
||||
|
||||
it('displays and focuses an error message when trying to navigate to a nonexistent page', function () {
|
||||
var teamsTabView = createTeamsTabView();
|
||||
teamsTabView.router.navigate('no_such_page', {trigger: true});
|
||||
@@ -49,12 +71,6 @@ define([
|
||||
expectFocus(teamsTabView.$('.warning'));
|
||||
});
|
||||
|
||||
it('does not interfere with anchor links to #content', function () {
|
||||
var teamsTabView = createTeamsTabView();
|
||||
teamsTabView.router.navigate('#content', {trigger: true});
|
||||
expect(teamsTabView.$('.warning')).toHaveClass('is-hidden');
|
||||
});
|
||||
|
||||
it('displays and focuses an error message when trying to navigate to a nonexistent topic', function () {
|
||||
var requests = AjaxHelpers.requests(this),
|
||||
teamsTabView = createTeamsTabView();
|
||||
@@ -94,6 +110,64 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
describe('Analytics Events', function () {
|
||||
SpecHelpers.withData({
|
||||
'fires a page view event for the topic page': [
|
||||
'topics/' + TeamSpecHelpers.testTopicID,
|
||||
{
|
||||
page_name: 'single-topic',
|
||||
topic_id: TeamSpecHelpers.testTopicID,
|
||||
team_id: null
|
||||
}
|
||||
],
|
||||
'fires a page view event for the team page': [
|
||||
'teams/' + TeamSpecHelpers.testTopicID + '/test_team_id',
|
||||
{
|
||||
page_name: 'single-team',
|
||||
topic_id: TeamSpecHelpers.testTopicID,
|
||||
team_id: 'test_team_id'
|
||||
}
|
||||
],
|
||||
'fires a page view event for the search team page': [
|
||||
'topics/' + TeamSpecHelpers.testTopicID + '/search',
|
||||
{
|
||||
page_name: 'search-teams',
|
||||
topic_id: TeamSpecHelpers.testTopicID,
|
||||
team_id: null
|
||||
}
|
||||
],
|
||||
'fires a page view event for the new team page': [
|
||||
'topics/' + TeamSpecHelpers.testTopicID + '/create-team',
|
||||
{
|
||||
page_name: 'new-team',
|
||||
topic_id: TeamSpecHelpers.testTopicID,
|
||||
team_id: null
|
||||
}
|
||||
],
|
||||
'fires a page view event for the edit team page': [
|
||||
'topics/' + TeamSpecHelpers.testTopicID + '/' + 'test_team_id/edit-team',
|
||||
{
|
||||
page_name: 'edit-team',
|
||||
topic_id: TeamSpecHelpers.testTopicID,
|
||||
team_id: 'test_team_id'
|
||||
}
|
||||
]
|
||||
}, function (url, expectedEvent) {
|
||||
if (url.indexOf('search') !== -1
|
||||
|| url.indexOf('create-team') !== -1
|
||||
|| url.indexOf('edit-team') !== -1) {
|
||||
debugger;
|
||||
}
|
||||
var requests = AjaxHelpers.requests(this),
|
||||
teamsTabView = createTeamsTabView();
|
||||
teamsTabView.router.navigate(url, {trigger: true});
|
||||
if (requests.length) {
|
||||
AjaxHelpers.respondWithJson(requests, {});
|
||||
}
|
||||
expect(Logger.log).toHaveBeenCalledWith('edx.team.page_viewed', expectedEvent);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Discussion privileges', function () {
|
||||
it('allows privileged access to any team', function () {
|
||||
var teamsTabView = createTeamsTabView({
|
||||
@@ -206,7 +280,7 @@ define([
|
||||
|
||||
// Navigate back to the teams list
|
||||
teamsTabView.$('.breadcrumbs a').last().click();
|
||||
verifyTeamsRequest(requests, {
|
||||
verifyTeamsRequest(removeTeamEvents(requests), {
|
||||
order_by: 'last_activity_at',
|
||||
text_search: ''
|
||||
});
|
||||
|
||||
23
lms/djangoapps/teams/static/teams/js/utils/team_analytics.js
Normal file
23
lms/djangoapps/teams/static/teams/js/utils/team_analytics.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Utility methods for emitting teams events. See the event spec:
|
||||
* https://openedx.atlassian.net/wiki/display/AN/Teams+Feature+Event+Design
|
||||
*/
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
|
||||
define([
|
||||
'logger'
|
||||
], function (Logger) {
|
||||
var TeamAnalytics = {
|
||||
emitPageViewed: function (page_name, topic_id, team_id) {
|
||||
Logger.log('edx.team.page_viewed', {
|
||||
page_name: page_name,
|
||||
topic_id: topic_id,
|
||||
team_id: team_id
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return TeamAnalytics;
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
@@ -7,12 +7,13 @@
|
||||
'common/js/components/views/search_field',
|
||||
'js/components/header/views/header',
|
||||
'js/components/header/models/header',
|
||||
'js/components/tabbed/views/tabbed_view',
|
||||
'teams/js/models/topic',
|
||||
'teams/js/collections/topic',
|
||||
'teams/js/models/team',
|
||||
'teams/js/collections/team',
|
||||
'teams/js/collections/team_membership',
|
||||
'teams/js/utils/team_analytics',
|
||||
'teams/js/views/teams_tabbed_view',
|
||||
'teams/js/views/topics',
|
||||
'teams/js/views/team_profile',
|
||||
'teams/js/views/my_teams',
|
||||
@@ -21,9 +22,9 @@
|
||||
'teams/js/views/team_profile_header_actions',
|
||||
'teams/js/views/team_utils',
|
||||
'text!teams/templates/teams_tab.underscore'],
|
||||
function (Backbone, _, gettext, SearchFieldView, HeaderView, HeaderModel, TabbedView,
|
||||
TopicModel, TopicCollection, TeamModel, TeamCollection, TeamMembershipCollection,
|
||||
TopicsView, TeamProfileView, MyTeamsView, TopicTeamsView, TeamEditView,
|
||||
function (Backbone, _, gettext, SearchFieldView, HeaderView, HeaderModel,
|
||||
TopicModel, TopicCollection, TeamModel, TeamCollection, TeamMembershipCollection, TeamAnalytics,
|
||||
TeamsTabbedView, TopicsView, TeamProfileView, MyTeamsView, TopicTeamsView, TeamEditView,
|
||||
TeamProfileHeaderActionsView, TeamUtils, teamsTemplate) {
|
||||
var TeamsHeaderModel = HeaderModel.extend({
|
||||
initialize: function () {
|
||||
@@ -118,7 +119,7 @@
|
||||
this.mainView = this.tabbedView = this.createViewWithHeader({
|
||||
title: gettext("Teams"),
|
||||
description: gettext("See all teams in your course, organized by topic. Join a team to collaborate with other learners who are interested in the same topic as you are."),
|
||||
mainView: new TabbedView({
|
||||
mainView: new TeamsTabbedView({
|
||||
tabs: [{
|
||||
title: gettext('My Team'),
|
||||
url: 'my-teams',
|
||||
@@ -180,6 +181,7 @@
|
||||
this.getTeamsView(topicID).done(function (teamsView) {
|
||||
self.teamsView = self.mainView = teamsView;
|
||||
self.render();
|
||||
TeamAnalytics.emitPageViewed('single-topic', topicID, null);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -205,6 +207,7 @@
|
||||
showSortControls: false
|
||||
});
|
||||
view.render();
|
||||
TeamAnalytics.emitPageViewed('search-teams', topicID, null);
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -227,6 +230,7 @@
|
||||
})
|
||||
});
|
||||
view.render();
|
||||
TeamAnalytics.emitPageViewed('new-team', topicID, null);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -254,6 +258,7 @@
|
||||
});
|
||||
self.mainView = editViewWithHeader;
|
||||
self.render();
|
||||
TeamAnalytics.emitPageViewed('edit-team', topicID, teamID);
|
||||
});
|
||||
});
|
||||
},
|
||||
@@ -340,6 +345,7 @@
|
||||
this.getBrowseTeamView(topicID, teamID).done(function (browseTeamView) {
|
||||
self.mainView = browseTeamView;
|
||||
self.render();
|
||||
TeamAnalytics.emitPageViewed('single-team', topicID, teamID);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* A custom TabbedView for Teams.
|
||||
*/
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
|
||||
define([
|
||||
'js/components/tabbed/views/tabbed_view',
|
||||
'teams/js/utils/team_analytics'
|
||||
], function (TabbedView, TeamAnalytics) {
|
||||
var TeamsTabbedView = TabbedView.extend({
|
||||
/**
|
||||
* Overrides TabbedView.prototype.setActiveTab in order to
|
||||
* log page viewed events.
|
||||
*/
|
||||
setActiveTab: function (index) {
|
||||
TabbedView.prototype.setActiveTab.call(this, index);
|
||||
TeamAnalytics.emitPageViewed(this.getTabMeta(index).tab.url, null, null);
|
||||
}
|
||||
});
|
||||
|
||||
return TeamsTabbedView;
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
@@ -59,16 +59,10 @@
|
||||
},
|
||||
|
||||
setActiveTab: function (index) {
|
||||
var tab, tabEl, view;
|
||||
if (typeof index === 'string') {
|
||||
tab = this.urlMap[index];
|
||||
tabEl = this.$('a[data-url='+index+']');
|
||||
}
|
||||
else {
|
||||
tab = this.tabs[index];
|
||||
tabEl = this.$('a[data-index='+index+']');
|
||||
}
|
||||
view = tab.view;
|
||||
var tabMeta = this.getTabMeta(index),
|
||||
tab = tabMeta.tab,
|
||||
tabEl = tabMeta.element,
|
||||
view = tab.view;
|
||||
this.$('a.is-active').removeClass('is-active').attr('aria-selected', 'false');
|
||||
tabEl.addClass('is-active').attr('aria-selected', 'true');
|
||||
view.setElement(this.$('.page-content-main')).render();
|
||||
@@ -81,6 +75,22 @@
|
||||
switchTab: function (event) {
|
||||
event.preventDefault();
|
||||
this.setActiveTab($(event.currentTarget).data('index'));
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the tab by name or index. Returns an object
|
||||
* encapsulating the tab object and its element.
|
||||
*/
|
||||
getTabMeta: function (tabNameOrIndex) {
|
||||
var tab, element;
|
||||
if (typeof tabNameOrIndex === 'string') {
|
||||
tab = this.urlMap[tabNameOrIndex];
|
||||
element = this.$('a[data-url='+tabNameOrIndex+']');
|
||||
} else {
|
||||
tab = this.tabs[tabNameOrIndex];
|
||||
element = this.$('a[data-index='+tabNameOrIndex+']');
|
||||
}
|
||||
return {'tab': tab, 'element': element};
|
||||
}
|
||||
});
|
||||
return TabbedView;
|
||||
|
||||
Reference in New Issue
Block a user