diff --git a/common/static/common/js/spec_helpers/ajax_helpers.js b/common/static/common/js/spec_helpers/ajax_helpers.js index bfcbe5971b..5140b2550e 100644 --- a/common/static/common/js/spec_helpers/ajax_helpers.js +++ b/common/static/common/js/spec_helpers/ajax_helpers.js @@ -1,5 +1,7 @@ -define(['sinon', 'underscore'], function(sinon, _) { - var fakeServer, fakeRequests, expectRequest, expectJsonRequest, expectPostRequest, +define(['sinon', 'underscore', 'URI'], function(sinon, _, URI) { + 'use strict'; + + var fakeServer, fakeRequests, expectRequest, expectJsonRequest, expectPostRequest, expectJsonRequestURL, respondWithJson, respondWithError, respondWithTextError, respondWithNoContent; /* These utility methods are used by Jasmine tests to create a mock server or @@ -68,6 +70,24 @@ define(['sinon', 'underscore'], function(sinon, _) { expect(JSON.parse(request.requestBody)).toEqual(jsonRequest); }; + /** + * Expect that a JSON request be made with the given URL and parameters. + * @param requests The collected requests + * @param expectedUrl The expected URL excluding the parameters + * @param expectedParameters An object representing the URL parameters + * @param requestIndex An optional index for the request (by default, the last request is used) + */ + expectJsonRequestURL = function(requests, expectedUrl, expectedParameters, requestIndex) { + var request, parameters; + if (_.isUndefined(requestIndex)) { + requestIndex = requests.length - 1; + } + request = requests[requestIndex]; + parameters = new URI(request.url).query(true); + delete parameters._; // Ignore the cache-busting argument + expect(parameters).toEqual(expectedParameters); + }; + /** * Intended for use with POST requests using application/x-www-form-urlencoded. */ @@ -136,6 +156,7 @@ define(['sinon', 'underscore'], function(sinon, _) { 'requests': fakeRequests, 'expectRequest': expectRequest, 'expectJsonRequest': expectJsonRequest, + 'expectJsonRequestURL': expectJsonRequestURL, 'expectPostRequest': expectPostRequest, 'respondWithJson': respondWithJson, 'respondWithError': respondWithError, diff --git a/common/test/acceptance/tests/lms/test_teams.py b/common/test/acceptance/tests/lms/test_teams.py index 8bf1af5b8f..f4832274f9 100644 --- a/common/test/acceptance/tests/lms/test_teams.py +++ b/common/test/acceptance/tests/lms/test_teams.py @@ -248,7 +248,7 @@ class MyTeamsTest(TeamsTabBase): self.assertEqual(len(self.my_teams_page.team_cards), 0, msg='Expected to see no team cards') self.assertEqual( self.my_teams_page.q(css='.page-content-main').text, - [u'You are not currently a member of any teams.'] + [u'You are not currently a member of any team.'] ) def test_member_of_a_team(self): @@ -530,7 +530,12 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase): self.browse_teams_page.go_to_page(1) self.verify_on_page(1, teams, 'Showing 1-10 out of 20 total', True) - def test_teams_membership(self): + @ddt.data( + ['Moderator', False] + ['Community TA', False], + ['Administrator', False] + ) + def test_create_team(self, role, should_join_team): """ Scenario: Team cards correctly reflect membership of the team. Given I am enrolled in a course with a team configuration and a topic @@ -540,6 +545,7 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase): Then I should see the correct page header And I should see the team for that topic And I should see that the team card shows my membership + When I visit the My Teams page """ teams = self.create_teams(self.topic, 1) self.browse_teams_page.visit() @@ -548,11 +554,10 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase): self.create_membership(self.user_info['username'], teams[0]['id']) self.browser.refresh() self.browse_teams_page.wait_for_ajax() - ## TODO: fix this! - # self.assertEqual( - # self.browse_teams_page.team_cards[0].find_element_by_css_selector('.member-count').text, - # '1 / 10 Members' - # ) + self.assertEqual( + self.browse_teams_page.team_cards[0].find_element_by_css_selector('.member-count').text, + '1 / 10 Members' + ) def test_navigation_links(self): """ diff --git a/lms/djangoapps/teams/static/teams/js/collections/base.js b/lms/djangoapps/teams/static/teams/js/collections/base.js new file mode 100644 index 0000000000..512ce2f3bc --- /dev/null +++ b/lms/djangoapps/teams/static/teams/js/collections/base.js @@ -0,0 +1,43 @@ +;(function (define) { + 'use strict'; + define(['common/js/components/collections/paging_collection'], + function(PagingCollection) { + var BaseCollection = PagingCollection.extend({ + initialize: function(options) { + PagingCollection.prototype.initialize.call(this); + + this.course_id = options.course_id; + this.perPage = options.per_page; + + this.teamEvents = options.teamEvents; + this.teamEvents.bind('teams:update', this.onUpdate, this); + this.isStale = false; + }, + + onUpdate: function(event) { + this.isStale = true; + }, + + /** + * Refreshes the collection if it has been marked as stale. + * @param force If true, it will always refresh. + * @returns {promise} Returns a promise representing the refresh + */ + refresh: function(force) { + var self = this, + deferred = $.Deferred(); + if (force || this.isStale) { + this.fetch() + .done(function() { + self.isStale = false; + deferred.resolve(); + }); + } else { + deferred.resolve(); + } + return deferred.promise(); + } + }); + return BaseCollection; + }); +}).call(this, define || RequireJS.define); diff --git a/lms/djangoapps/teams/static/teams/js/collections/team.js b/lms/djangoapps/teams/static/teams/js/collections/team.js index c64a3c10ff..417f7cdf4e 100644 --- a/lms/djangoapps/teams/static/teams/js/collections/team.js +++ b/lms/djangoapps/teams/static/teams/js/collections/team.js @@ -1,18 +1,22 @@ ;(function (define) { 'use strict'; - define(['common/js/components/collections/paging_collection', 'teams/js/models/team', 'gettext'], - function(PagingCollection, TeamModel, gettext) { - var TeamCollection = PagingCollection.extend({ + define(['teams/js/collections/base', 'teams/js/models/team', 'gettext'], + function(BaseCollection, TeamModel, gettext) { + var TeamCollection = BaseCollection.extend({ initialize: function(teams, options) { - PagingCollection.prototype.initialize.call(this); + var self = this; + BaseCollection.prototype.initialize.call(this, options); - this.course_id = options.course_id; - this.server_api['topic_id'] = this.topic_id = options.topic_id; - this.server_api['expand'] = 'user'; - this.perPage = options.per_page; - this.server_api['course_id'] = function () { return encodeURIComponent(this.course_id); }; - this.server_api['order_by'] = function () { return 'name'; }; // TODO surface sort order in UI - delete this.server_api['sort_order']; // Sort order is not specified for the Team API + this.server_api = _.extend( + { + topic_id: this.topic_id = options.topic_id, + expand: 'user', + course_id: function () { return encodeURIComponent(self.course_id); }, + order_by: function () { return 'name'; } // TODO surface sort order in UI + }, + BaseCollection.prototype.server_api + ); + delete this.server_api.sort_order; // Sort order is not specified for the Team API this.registerSortableField('name', gettext('name')); this.registerSortableField('open_slots', gettext('open_slots')); @@ -21,5 +25,5 @@ model: TeamModel }); return TeamCollection; - }); + }); }).call(this, define || RequireJS.define); diff --git a/lms/djangoapps/teams/static/teams/js/collections/team_membership.js b/lms/djangoapps/teams/static/teams/js/collections/team_membership.js index bec4df8e9c..9478d65d60 100644 --- a/lms/djangoapps/teams/static/teams/js/collections/team_membership.js +++ b/lms/djangoapps/teams/static/teams/js/collections/team_membership.js @@ -1,18 +1,24 @@ ;(function (define) { 'use strict'; - define(['common/js/components/collections/paging_collection', 'teams/js/models/team_membership'], - function(PagingCollection, TeamMembershipModel) { - var TeamMembershipCollection = PagingCollection.extend({ + define(['teams/js/collections/base', 'teams/js/models/team_membership'], + function(BaseCollection, TeamMembershipModel) { + var TeamMembershipCollection = BaseCollection.extend({ initialize: function(team_memberships, options) { - PagingCollection.prototype.initialize.call(this); + var self = this; + BaseCollection.prototype.initialize.call(this, options); - this.course_id = options.course_id; + this.perPage = options.per_page || 10; this.username = options.username; this.privileged = options.privileged; - this.perPage = options.per_page || 10; - this.server_api['expand'] = 'team'; - this.server_api['course_id'] = function () { return encodeURIComponent(options.course_id); }; - this.server_api['username'] = this.username; + + this.server_api = _.extend( + { + expand: 'team', + username: this.username, + course_id: function () { return encodeURIComponent(self.course_id); } + }, + BaseCollection.prototype.server_api + ); delete this.server_api['sort_order']; // Sort order is not specified for the TeamMembership API delete this.server_api['order_by']; // Order by is not specified for the TeamMembership API }, @@ -28,5 +34,5 @@ } }); return TeamMembershipCollection; - }); + }); }).call(this, define || RequireJS.define); diff --git a/lms/djangoapps/teams/static/teams/js/collections/topic.js b/lms/djangoapps/teams/static/teams/js/collections/topic.js index 538e339762..e6b4c8734b 100644 --- a/lms/djangoapps/teams/static/teams/js/collections/topic.js +++ b/lms/djangoapps/teams/static/teams/js/collections/topic.js @@ -1,15 +1,22 @@ ;(function (define) { 'use strict'; - define(['common/js/components/collections/paging_collection', 'teams/js/models/topic', 'gettext'], - function(PagingCollection, TopicModel, gettext) { - var TopicCollection = PagingCollection.extend({ + define(['teams/js/collections/base', 'teams/js/models/topic', 'gettext'], + function(BaseCollection, TopicModel, gettext) { + var TopicCollection = BaseCollection.extend({ initialize: function(topics, options) { - PagingCollection.prototype.initialize.call(this); + var self = this; + + BaseCollection.prototype.initialize.call(this, options); - this.course_id = options.course_id; this.perPage = topics.results.length; - this.server_api['course_id'] = function () { return encodeURIComponent(this.course_id); }; - this.server_api['order_by'] = function () { return this.sortField; }; + + this.server_api = _.extend( + { + course_id: function () { return encodeURIComponent(self.course_id); }, + order_by: function () { return this.sortField; } + }, + BaseCollection.prototype.server_api + ); delete this.server_api['sort_order']; // Sort order is not specified for the Team API this.registerSortableField('name', gettext('name')); @@ -17,8 +24,12 @@ this.registerSortableField('team_count', gettext('team count')); }, + onUpdate: function(event) { + this.isStale = event.action === 'create'; + }, + model: TopicModel }); return TopicCollection; - }); + }); }).call(this, define || RequireJS.define); diff --git a/lms/djangoapps/teams/static/teams/js/spec/collections/topic_collection_spec.js b/lms/djangoapps/teams/static/teams/js/spec/collections/topic_collection_spec.js index 6942fbb813..1598db4e87 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/collections/topic_collection_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/collections/topic_collection_spec.js @@ -1,5 +1,5 @@ -define(['URI', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/collections/topic'], - function (URI, _, AjaxHelpers, TopicCollection) { +define(['backbone', 'URI', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/collections/topic'], + function (Backbone, URI, _, AjaxHelpers, TopicCollection) { 'use strict'; describe('TopicCollection', function () { var topicCollection; @@ -39,7 +39,11 @@ define(['URI', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/co ], "sort_order": "name" }, - {course_id: 'my/course/id', parse: true}); + { + teamEvents:_.clone(Backbone.Events), + course_id: 'my/course/id', + parse: true + }); }); var testRequestParam = function (self, param, value) { diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_spec.js index 253bcebf41..da0b4ad674 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_spec.js @@ -3,13 +3,13 @@ define([ 'underscore', 'backbone', 'common/js/spec_helpers/ajax_helpers', - 'teams/js/views/edit_team' -], function ($, _, Backbone, AjaxHelpers, TeamEditView) { + 'teams/js/views/edit_team', + 'teams/js/spec_helpers/team_spec_helpers' +], function ($, _, Backbone, AjaxHelpers, TeamEditView, TeamSpecHelpers) { 'use strict'; describe('EditTeam', function () { - var teamEditView, - teamsUrl = '/api/team/v0/teams/', + var teamsUrl = '/api/team/v0/teams/', teamsData = { id: null, name: "TeamName", @@ -22,7 +22,7 @@ define([ language: "a", membership: [] }, - verifyValidation = function (requests, fieldsData) { + verifyValidation = function (requests, teamEditView, fieldsData) { _.each(fieldsData, function (fieldData) { teamEditView.$(fieldData[0]).val(fieldData[1]); }); @@ -45,24 +45,11 @@ define([ }); expect(requests.length).toBe(0); - }, - expectContent = function (selector, text) { - expect(teamEditView.$(selector).text().trim()).toBe(text); - }, - verifyDropdownData = function (selector, expectedItems) { - var options = teamEditView.$(selector)[0].options; - var renderedItems = $.map(options, function( elem ) { - return [[elem.value, elem.text]]; - }); - for (var i = 0; i < expectedItems.length; i++) { - expect(renderedItems).toContain(expectedItems[i]); - } }; - beforeEach(function () { - setFixtures('
'); - spyOn(Backbone.history, 'navigate'); - teamEditView = new TeamEditView({ + var createTeamEditView = function() { + return new TeamEditView({ + teamEvents: TeamSpecHelpers.teamEvents, el: $('.teams-content'), teamParams: { teamsUrl: teamsUrl, @@ -73,6 +60,11 @@ define([ countries: [['c', 'ccc'], ['d', 'ddd']] } }).render(); + }; + + beforeEach(function () { + setFixtures(''); + spyOn(Backbone.history, 'navigate'); }); it('can render itself correctly', function () { @@ -82,7 +74,8 @@ define([ '.u-field-optional_description', '.u-field-language', '.u-field-country' - ]; + ], + teamEditView = createTeamEditView(); _.each(fieldClasses, function (fieldClass) { expect(teamEditView.$el.find(fieldClass).length).toBe(1); @@ -93,7 +86,8 @@ define([ }); it('can create a team', function () { - var requests = AjaxHelpers.requests(this); + var requests = AjaxHelpers.requests(this), + teamEditView = createTeamEditView(); teamEditView.$('.u-field-name input').val(teamsData.name); teamEditView.$('.u-field-textarea textarea').val(teamsData.description); @@ -109,46 +103,49 @@ define([ }); it('shows validation error message when field is empty', function () { - var requests = AjaxHelpers.requests(this); - verifyValidation(requests, [ + var requests = AjaxHelpers.requests(this), + teamEditView = createTeamEditView(); + verifyValidation(requests, teamEditView, [ ['.u-field-name input', 'Name', 'success'], ['.u-field-textarea textarea', '', 'error'] ]); teamEditView.render(); - verifyValidation(requests, [ + verifyValidation(requests, teamEditView, [ ['.u-field-name input', '', 'error'], ['.u-field-textarea textarea', 'description', 'success'] ]); teamEditView.render(); - verifyValidation(requests, [ + verifyValidation(requests, teamEditView, [ ['.u-field-name input', '', 'error'], ['.u-field-textarea textarea', '', 'error'] ]); }); it('shows validation error message when field value length exceeded the limit', function () { - var requests = AjaxHelpers.requests(this); - var teamName = new Array(500 + 1).join( '$' ); - var teamDescription = new Array(500 + 1).join( '$' ); + var requests = AjaxHelpers.requests(this), + teamEditView = createTeamEditView(), + teamName = new Array(500 + 1).join( '$'), + teamDescription = new Array(500 + 1).join( '$' ); - verifyValidation(requests, [ + verifyValidation(requests, teamEditView, [ ['.u-field-name input', teamName, 'error'], ['.u-field-textarea textarea', 'description', 'success'] ]); teamEditView.render(); - verifyValidation(requests, [ + verifyValidation(requests, teamEditView, [ ['.u-field-name input', 'name', 'success'], ['.u-field-textarea textarea', teamDescription, 'error'] ]); teamEditView.render(); - verifyValidation(requests, [ + verifyValidation(requests, teamEditView, [ ['.u-field-name input', teamName, 'error'], ['.u-field-textarea textarea', teamDescription, 'error'] ]); }); it("shows an error message for HTTP 500", function () { - var requests = AjaxHelpers.requests(this); + var teamEditView = createTeamEditView(), + requests = AjaxHelpers.requests(this); teamEditView.$('.u-field-name input').val(teamsData.name); teamEditView.$('.u-field-textarea textarea').val(teamsData.description); @@ -163,6 +160,7 @@ define([ }); it("changes route on cancel click", function () { + var teamEditView = createTeamEditView(); teamEditView.$('.create-team.form-actions .action-cancel').click(); expect(Backbone.history.navigate.calls[0].args).toContain('topics/awesomeness'); }); diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/my_teams_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/my_teams_spec.js index 6893f02bb6..188a9fc202 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/my_teams_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/my_teams_spec.js @@ -3,8 +3,9 @@ define([ 'teams/js/collections/team', 'teams/js/collections/team_membership', 'teams/js/views/my_teams', - 'teams/js/spec_helpers/team_spec_helpers' -], function (Backbone, TeamCollection, TeamMembershipCollection, MyTeamsView, TeamSpecHelpers) { + 'teams/js/spec_helpers/team_spec_helpers', + 'common/js/spec_helpers/ajax_helpers' +], function (Backbone, TeamCollection, TeamMembershipCollection, MyTeamsView, TeamSpecHelpers, AjaxHelpers) { 'use strict'; describe('My Teams View', function () { beforeEach(function () { @@ -28,26 +29,51 @@ define([ it('can render itself', function () { var teamMembershipsData = TeamSpecHelpers.createMockTeamMembershipsData(1, 5), teamMemberships = TeamSpecHelpers.createMockTeamMemberships(teamMembershipsData), - teamsView = createMyTeamsView({ + myTeamsView = createMyTeamsView({ teams: teamMemberships, teamMemberships: teamMemberships }); - TeamSpecHelpers.verifyCards(teamsView, teamMembershipsData); + TeamSpecHelpers.verifyCards(myTeamsView, teamMembershipsData); // Verify that there is no header or footer - expect(teamsView.$('.teams-paging-header').text().trim()).toBe(''); - expect(teamsView.$('.teams-paging-footer').text().trim()).toBe(''); + expect(myTeamsView.$('.teams-paging-header').text().trim()).toBe(''); + expect(myTeamsView.$('.teams-paging-footer').text().trim()).toBe(''); }); it('shows a message when the user is not a member of any teams', function () { var teamMemberships = TeamSpecHelpers.createMockTeamMemberships([]), - teamsView = createMyTeamsView({ + myTeamsView = createMyTeamsView({ teams: teamMemberships, teamMemberships: teamMemberships }); - TeamSpecHelpers.verifyCards(teamsView, []); - expect(teamsView.$el.text().trim()).toBe('You are not currently a member of any teams.'); + TeamSpecHelpers.verifyCards(myTeamsView, []); + expect(myTeamsView.$el.text().trim()).toBe('You are not currently a member of any team.'); + }); + + it('refreshes a stale membership collection when rendering', function() { + var requests = AjaxHelpers.requests(this), + teamMemberships = TeamSpecHelpers.createMockTeamMemberships([]), + myTeamsView = createMyTeamsView({ + teams: teamMemberships, + teamMemberships: teamMemberships + }); + TeamSpecHelpers.verifyCards(myTeamsView, []); + expect(myTeamsView.$el.text().trim()).toBe('You are not currently a member of any team.'); + teamMemberships.teamEvents.trigger('teams:update', { action: 'create' }); + myTeamsView.render(); + AjaxHelpers.expectJsonRequestURL( + requests, + 'foo', + { + expand : 'team', + username : 'testUser', + course_id : 'my/course/id', + page : '1', + page_size : '10' + } + ); + AjaxHelpers.respondWithJson(requests, {}); }); }); }); diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/team_join_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/team_join_spec.js index 8ddad5ff64..93f8adb6a1 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/team_join_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/team_join_spec.js @@ -1,8 +1,7 @@ define([ - 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/models/team', - 'teams/js/spec_helpers/team_spec_helpers', - 'teams/js/views/team_join' -], function (_, AjaxHelpers, TeamModel, TeamSpecHelpers, TeamJoinView) { + 'backbone', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'teams/js/models/team', + 'teams/js/views/team_join', 'teams/js/spec_helpers/team_spec_helpers' +], function (Backbone, _, AjaxHelpers, TeamModel, TeamJoinView, TeamSpecHelpers) { 'use strict'; describe('TeamJoinView', function () { var createTeamsUrl, @@ -63,6 +62,7 @@ define([ var teamJoinView = new TeamJoinView( { courseID: TeamSpecHelpers.testCourseID, + teamEvents: TeamSpecHelpers.teamEvents, model: model, teamsUrl: createTeamsUrl(teamId), maxTeamSize: maxTeamSize, diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_spec.js index 9d08a7d49b..4f97096113 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_spec.js @@ -5,16 +5,18 @@ define([ ], function (_, AjaxHelpers, TeamModel, TeamProfileView, TeamSpecHelpers, DiscussionSpecHelper) { 'use strict'; describe('TeamProfileView', function () { - var profileView, createTeamProfileView, createTeamModelData, teamModel, + var profileView, createTeamProfileView, createTeamModelData, clickLeaveTeam, + teamModel, + leaveTeamLinkSelector = '.leave-team-link', DEFAULT_MEMBERSHIP = [ { 'user': { 'username': 'bilbo', 'profile_image': { 'has_image': true, - 'image_url_medium': '/image-url' - } + 'image_url_medium': '/image-url' } + } } ]; @@ -38,6 +40,7 @@ define([ createTeamProfileView = function(requests, options) { teamModel = new TeamModel(createTeamModelData(options), { parse: true }); profileView = new TeamProfileView({ + teamEvents: TeamSpecHelpers.teamEvents, courseID: TeamSpecHelpers.testCourseID, model: teamModel, maxTeamSize: options.maxTeamSize || 3, @@ -71,6 +74,21 @@ define([ return profileView; }; + clickLeaveTeam = function(requests, view) { + expect(view.$(leaveTeamLinkSelector).length).toBe(1); + + // click on Leave Team link under Team Details + view.$(leaveTeamLinkSelector).click(); + + // expect a request to DELETE the team membership + AjaxHelpers.expectJsonRequest(requests, 'DELETE', 'api/team/v0/team_membership/test-team,bilbo'); + AjaxHelpers.respondWithNoContent(requests); + + // expect a request to refetch the user's team memberships + AjaxHelpers.expectJsonRequest(requests, 'GET', '/api/team/v0/teams/test-team'); + AjaxHelpers.respondWithJson(requests, createTeamModelData({country: 'US', language: 'en'})); + }; + describe('DiscussionsView', function() { it('can render itself', function () { var requests = AjaxHelpers.requests(this), @@ -84,6 +102,7 @@ define([ expect(view.$('.new-post-btn').length).toEqual(0); teamModel.set('membership', DEFAULT_MEMBERSHIP); // This should re-render the view. + view.render(); expect(view.$('.new-post-btn').length).toEqual(1); }); @@ -92,7 +111,7 @@ define([ view = createTeamProfileView(requests, {membership: DEFAULT_MEMBERSHIP}); expect(view.$('.new-post-btn').length).toEqual(1); - teamModel.set('membership', []); + clickLeaveTeam(requests, view); expect(view.$('.new-post-btn').length).toEqual(0); }); }); @@ -119,7 +138,10 @@ define([ assertTeamDetails(view, 0, false); expect(view.$('.team-user-membership-status').length).toBe(0); + // Verify that the leave team link is not present. + expect(view.$(leaveTeamLinkSelector).length).toBe(0); }); + it('cannot see the country & language if empty', function() { var requests = AjaxHelpers.requests(this); var view = createTeamProfileView(requests, {}); @@ -145,29 +167,21 @@ define([ // assert user profile page url. expect(view.$('.member-profile').attr('href')).toBe('/u/bilbo'); + //Verify that the leave team link is present + expect(view.$(leaveTeamLinkSelector).text()).toContain('Leave Team'); }); + it('can leave team successfully', function() { var requests = AjaxHelpers.requests(this); - var leaveTeamLinkSelector = '.leave-team-link'; var view = createTeamProfileView( - requests, { country: 'US', language: 'en', membership: DEFAULT_MEMBERSHIP} + requests, {country: 'US', language: 'en', membership: DEFAULT_MEMBERSHIP} ); assertTeamDetails(view, 1, true); - - expect(view.$(leaveTeamLinkSelector).length).toBe(1); - - // click on Leave Team link under Team Details - view.$(leaveTeamLinkSelector).click(); - - // response to DELETE - AjaxHelpers.respondWithNoContent(requests); - - // response to model fetch request - AjaxHelpers.respondWithJson(requests, createTeamModelData({country: 'US', language: 'en'})); - + clickLeaveTeam(requests, view); assertTeamDetails(view, 0, false); }); + it('shows correct error messages', function () { var requests = AjaxHelpers.requests(this); diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/topic_card_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/topic_card_spec.js index 332d895716..605681681e 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/topic_card_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/topic_card_spec.js @@ -5,11 +5,8 @@ define(['jquery', function ($, _, TopicCardView, Topic) { describe('topic card view', function () { - var view; - - beforeEach(function () { - spyOn(TopicCardView.prototype, 'action'); - view = new TopicCardView({ + var createTopicCardView = function() { + return new TopicCardView({ model: new Topic({ 'id': 'renewables', 'name': 'Renewable Energy', @@ -17,9 +14,14 @@ define(['jquery', 'team_count': 34 }) }); + }; + + beforeEach(function () { + spyOn(TopicCardView.prototype, 'action'); }); it('can render itself', function () { + var view = createTopicCardView(); expect(view.$el).toHaveClass('square-card'); expect(view.$el.find('.card-title').text()).toContain('Renewable Energy'); expect(view.$el.find('.card-description').text()).toContain('changes in <ⓡⓔⓝⓔⓦⓐⓑⓛⓔ> ʎƃɹǝuǝ'); @@ -28,6 +30,7 @@ define(['jquery', }); it('navigates when action button is clicked', function () { + var view = createTopicCardView(); view.$el.find('.action').trigger('click'); // TODO test actual navigation once implemented expect(view.action).toHaveBeenCalled(); diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/topic_teams_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/topic_teams_spec.js index d539a2723f..e923eb7280 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/topic_teams_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/topic_teams_spec.js @@ -3,8 +3,9 @@ define([ 'teams/js/collections/team', 'teams/js/collections/team_membership', 'teams/js/views/topic_teams', - 'teams/js/spec_helpers/team_spec_helpers' -], function (Backbone, TeamCollection, TeamMembershipCollection, TopicTeamsView, TeamSpecHelpers) { + 'teams/js/spec_helpers/team_spec_helpers', + 'common/js/spec_helpers/ajax_helpers' +], function (Backbone, TeamCollection, TeamMembershipCollection, TopicTeamsView, TeamSpecHelpers, AjaxHelpers) { 'use strict'; describe('Topic Teams View', function () { var createTopicTeamsView = function(options) { @@ -21,6 +22,24 @@ define([ }).render(); }; + var verifyActions = function(teamsView, options) { + if (!options) { + options = {showActions: true}; + } + var expectedTitle = 'Are you having trouble finding a team to join?', + expectedMessage = 'Try browsing all teams or searching team descriptions. If you ' + + 'still can\'t find a team to join, create a new team in this topic.', + title = teamsView.$('.title').text().trim(), + message = teamsView.$('.copy').text().trim(); + if (options.showActions) { + expect(title).toBe(expectedTitle); + expect(message).toBe(expectedMessage); + } else { + expect(title).not.toBe(expectedTitle); + expect(message).not.toBe(expectedMessage); + } + }; + beforeEach(function () { setFixtures(''); }); @@ -39,12 +58,7 @@ define([ expect(footerEl).not.toHaveClass('hidden'); TeamSpecHelpers.verifyCards(teamsView, testTeamData); - - expect(teamsView.$('.title').text()).toBe('Are you having trouble finding a team to join?'); - expect(teamsView.$('.copy').text()).toBe( - "Try browsing all teams or searching team descriptions. If you " + - "still can't find a team to join, create a new team in this topic." - ); + verifyActions(teamsView); }); it('can browse all teams', function () { @@ -74,9 +88,7 @@ define([ it('does not show actions for a user already in a team', function () { var teamsView = createTopicTeamsView({}); - expect(teamsView.$el.text()).not.toContain( - 'Are you having trouble finding a team to join?' - ); + verifyActions(teamsView, {showActions: false}); }); it('shows actions for a privileged user already in a team', function () { @@ -85,9 +97,32 @@ define([ { privileged: true } ), teamsView = createTopicTeamsView({ teamMemberships: staffMembership }); - expect(teamsView.$el.text()).toContain( - 'Are you having trouble finding a team to join?' - ); + verifyActions(teamsView); }); + + /* + // TODO: make this ready for prime time + it('refreshes when the team membership changes', function() { + var requests = AjaxHelpers.requests(this), + teamMemberships = TeamSpecHelpers.createMockTeamMemberships([]), + teamsView = createTopicTeamsView({ teamMemberships: teamMemberships }); + verifyActions(teamsView, {showActions: true}); + teamMemberships.teamEvents.trigger('teams:update', { action: 'create' }); + teamsView.render(); + AjaxHelpers.expectJsonRequestURL( + requests, + 'foo', + { + expand : 'team', + username : 'testUser', + course_id : 'my/course/id', + page : '1', + page_size : '10' + } + ); + AjaxHelpers.respondWithJson(requests, {}); + verifyActions(teamsView, {showActions: false}); + }); + */ }); }); diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/topics_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/topics_spec.js index 3a4bade0aa..af764098a5 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/topics_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/topics_spec.js @@ -1,9 +1,10 @@ define([ - 'teams/js/collections/topic', 'teams/js/views/topics' -], function (TopicCollection, TopicsView) { + 'backbone', 'teams/js/collections/topic', 'teams/js/views/topics', + 'teams/js/spec_helpers/team_spec_helpers' +], function (Backbone, TopicCollection, TopicsView, TeamSpecHelpers) { 'use strict'; describe('TopicsView', function () { - var initialTopics, topicCollection, topicsView, + var initialTopics, topicCollection, createTopicsView, generateTopics = function (startIndex, stopIndex) { return _.map(_.range(startIndex, stopIndex + 1), function (i) { return { @@ -15,6 +16,14 @@ define([ }); }; + createTopicsView = function() { + return new TopicsView({ + teamEvents: TeamSpecHelpers.teamEvents, + el: '.topics-container', + collection: topicCollection + }).render(); + }; + beforeEach(function () { setFixtures(''); initialTopics = generateTopics(1, 5); @@ -26,13 +35,17 @@ define([ "start": 0, "results": initialTopics }, - {course_id: 'my/course/id', parse: true} + { + teamEvents: TeamSpecHelpers.teamEvents, + course_id: 'my/course/id', + parse: true + } ); - topicsView = new TopicsView({el: '.topics-container', collection: topicCollection}).render(); }); it('can render the first of many pages', function () { - var footerEl = topicsView.$('.topics-paging-footer'), + var topicsView = createTopicsView(), + footerEl = topicsView.$('.topics-paging-footer'), topicCards = topicsView.$('.topic-card'); expect(topicsView.$('.topics-paging-header').text()).toMatch('Showing 1-5 out of 6 total'); _.each(initialTopics, function (topic, index) { diff --git a/lms/djangoapps/teams/static/teams/js/spec_helpers/team_spec_helpers.js b/lms/djangoapps/teams/static/teams/js/spec_helpers/team_spec_helpers.js index 80a35e59c9..75f1bc2734 100644 --- a/lms/djangoapps/teams/static/teams/js/spec_helpers/team_spec_helpers.js +++ b/lms/djangoapps/teams/static/teams/js/spec_helpers/team_spec_helpers.js @@ -1,13 +1,15 @@ define([ + 'backbone', 'underscore', 'teams/js/collections/team', 'teams/js/collections/team_membership', -], function (_, TeamCollection, TeamMembershipCollection) { +], function (Backbone, _, TeamCollection, TeamMembershipCollection) { 'use strict'; var createMockPostResponse, createMockDiscussionResponse, createAnnotatedContentInfo, createMockThreadResponse, testCourseID = 'course/1', testUser = 'testUser', testTeamDiscussionID = "12345", + teamEvents = _.clone(Backbone.Events), testCountries = [ ['', ''], ['US', 'United States'], @@ -47,6 +49,7 @@ define([ results: teamData }, { + teamEvents: teamEvents, course_id: 'my/course/id', parse: true } @@ -79,6 +82,7 @@ define([ results: teamMembershipData }, _.extend(_.extend({}, { + teamEvents: teamEvents, course_id: 'my/course/id', parse: true, url: 'api/teams/team_memberships', @@ -225,6 +229,7 @@ define([ }; return { + teamEvents: teamEvents, testCourseID: testCourseID, testUser: testUser, testCountries: testCountries, diff --git a/lms/djangoapps/teams/static/teams/js/views/edit_team.js b/lms/djangoapps/teams/static/teams/js/views/edit_team.js index 556cecbf38..30698f6e14 100644 --- a/lms/djangoapps/teams/static/teams/js/views/edit_team.js +++ b/lms/djangoapps/teams/static/teams/js/views/edit_team.js @@ -20,6 +20,7 @@ }, initialize: function(options) { + this.teamEvents = options.teamEvents; this.courseID = options.teamParams.courseID; this.topicID = options.teamParams.topicID; this.collection = options.collection; @@ -28,7 +29,7 @@ this.countries = options.teamParams.countries; this.primaryButtonTitle = options.primaryButtonTitle || 'Submit'; - _.bindAll(this, 'goBackToTopic', 'createTeam'); + _.bindAll(this, 'goBackToTopic', 'createTeam'); this.teamModel = new TeamModel({}); this.teamModel.url = this.teamsUrl; @@ -113,6 +114,10 @@ this.teamModel.save(data, { wait: true }) .done(function(result) { + view.teamEvents.trigger('teams:update', { + action: 'create', + team: result + }); Backbone.history.navigate( 'teams/' + view.topicID + '/' + view.teamModel.id, {trigger: true} @@ -175,10 +180,10 @@ if (screenReaderMessage) { this.$('.screen-reader-message').text(screenReaderMessage); } - }, + }, - goBackToTopic: function () { - Backbone.history.navigate('topics/' + this.topicID, {trigger: true}); + goBackToTopic: function () { + Backbone.history.navigate('topics/' + this.topicID, {trigger: true}); } }); }); diff --git a/lms/djangoapps/teams/static/teams/js/views/my_teams.js b/lms/djangoapps/teams/static/teams/js/views/my_teams.js index 30617098b6..18ea2ea90b 100644 --- a/lms/djangoapps/teams/static/teams/js/views/my_teams.js +++ b/lms/djangoapps/teams/static/teams/js/views/my_teams.js @@ -5,10 +5,17 @@ function (Backbone, gettext, TeamsView) { var MyTeamsView = TeamsView.extend({ render: function() { - TeamsView.prototype.render.call(this); - if (this.collection.length === 0) { - this.$el.append('' + gettext('You are not currently a member of any teams.') + '
'); + var view = this; + if (this.collection.isStale) { + this.$el.html(''); } + this.collection.refresh() + .done(function() { + TeamsView.prototype.render.call(view); + if (view.collection.length === 0) { + view.$el.append('' + gettext('You are not currently a member of any team.') + '
'); + } + }); return this; }, diff --git a/lms/djangoapps/teams/static/teams/js/views/team_join.js b/lms/djangoapps/teams/static/teams/js/views/team_join.js index 524ebcc6bd..c9de1e2838 100644 --- a/lms/djangoapps/teams/static/teams/js/views/team_join.js +++ b/lms/djangoapps/teams/static/teams/js/views/team_join.js @@ -1,108 +1,114 @@ ;(function (define) { -'use strict'; + 'use strict'; -define(['backbone', - 'underscore', - 'gettext', - 'teams/js/views/team_utils', - 'text!teams/templates/team-join.underscore'], - function (Backbone, _, gettext, TeamUtils, teamJoinTemplate) { - return Backbone.View.extend({ + define(['backbone', + 'underscore', + 'gettext', + 'teams/js/views/team_utils', + 'text!teams/templates/team-join.underscore'], + function (Backbone, _, gettext, TeamUtils, teamJoinTemplate) { + return Backbone.View.extend({ - errorMessage: gettext("An error occurred. Try again."), - alreadyMemberMessage: gettext("You already belong to another team."), - teamFullMessage: gettext("This team is full."), + errorMessage: gettext("An error occurred. Try again."), + alreadyMemberMessage: gettext("You already belong to another team."), + teamFullMessage: gettext("This team is full."), - events: { - "click .action-primary": "joinTeam" - }, + events: { + "click .action-primary": "joinTeam" + }, - initialize: function(options) { - this.template = _.template(teamJoinTemplate); - this.courseID = options.courseID; - this.maxTeamSize = options.maxTeamSize; - this.currentUsername = options.currentUsername; - this.teamMembershipsUrl = options.teamMembershipsUrl; - _.bindAll(this, 'render', 'joinTeam', 'getUserTeamInfo'); - this.listenTo(this.model, "change", this.render); - }, + initialize: function(options) { + this.teamEvents = options.teamEvents; + this.template = _.template(teamJoinTemplate); + this.courseID = options.courseID; + this.maxTeamSize = options.maxTeamSize; + this.currentUsername = options.currentUsername; + this.teamMembershipsUrl = options.teamMembershipsUrl; + _.bindAll(this, 'render', 'joinTeam', 'getUserTeamInfo'); + this.listenTo(this.model, "change", this.render); + }, - render: function() { - var message, - showButton, - teamHasSpace; + render: function() { + var view = this, + message, + showButton, + teamHasSpace; + this.getUserTeamInfo(this.currentUsername, view.maxTeamSize).done(function (info) { + teamHasSpace = info.teamHasSpace; - var view = this; - this.getUserTeamInfo(this.currentUsername, view.maxTeamSize).done(function (info) { - teamHasSpace = info.teamHasSpace; + // if user is the member of current team then we wouldn't show anything + if (!info.memberOfCurrentTeam) { + showButton = !info.alreadyMember && teamHasSpace; - // if user is the member of current team then we wouldn't show anything - if (!info.memberOfCurrentTeam) { - showButton = !info.alreadyMember && teamHasSpace; + if (info.alreadyMember) { + message = info.memberOfCurrentTeam ? '' : view.alreadyMemberMessage; + } else if (!teamHasSpace) { + message = view.teamFullMessage; + } + } - if (info.alreadyMember) { - message = info.memberOfCurrentTeam ? '' : view.alreadyMemberMessage; - } else if (!teamHasSpace) { - message = view.teamFullMessage; - } - } + view.$el.html(view.template({showButton: showButton, message: message})); + }); + return view; + }, - view.$el.html(view.template({showButton: showButton, message: message})); - }); - return view; - }, + joinTeam: function () { + var view = this; + $.ajax({ + type: 'POST', + url: view.teamMembershipsUrl, + data: {'username': view.currentUsername, 'team_id': view.model.get('id')} + }).done(function (data) { + view.model.fetch() + .done(function() { + view.teamEvents.trigger('teams:update', { + action: 'join', + team: view.model + }); + }); + }).fail(function (data) { + TeamUtils.parseAndShowMessage(data, view.errorMessage); + }); + }, - joinTeam: function () { - var view = this; - $.ajax({ - type: 'POST', - url: view.teamMembershipsUrl, - data: {'username': view.currentUsername, 'team_id': view.model.get('id')} - }).done(function (data) { - view.model.fetch({}); - }).fail(function (data) { - TeamUtils.parseAndShowMessage(data, view.errorMessage); - }); - }, + getUserTeamInfo: function (username, maxTeamSize) { + var deferred = $.Deferred(); + var info = { + alreadyMember: false, + memberOfCurrentTeam: false, + teamHasSpace: false + }; - getUserTeamInfo: function (username, maxTeamSize) { - var deferred = $.Deferred(); - var info = { - alreadyMember: false, - memberOfCurrentTeam: false, - teamHasSpace: false - }; + info.memberOfCurrentTeam = TeamUtils.isUserMemberOfTeam(this.model.get('membership'), username); + var teamHasSpace = this.model.get('membership').length < maxTeamSize; - info.memberOfCurrentTeam = TeamUtils.isUserMemberOfTeam(this.model.get('membership'), username); - var teamHasSpace = this.model.get('membership').length < maxTeamSize; + if (info.memberOfCurrentTeam) { + info.alreadyMember = true; + info.memberOfCurrentTeam = true; + deferred.resolve(info); + } else { + if (teamHasSpace) { + var view = this; + $.ajax({ + type: 'GET', + url: view.teamMembershipsUrl, + data: {'username': username, 'course_id': view.courseID} + }).done(function (data) { + info.alreadyMember = (data.count > 0); + info.memberOfCurrentTeam = false; + info.teamHasSpace = teamHasSpace; + deferred.resolve(info); + }).fail(function (data) { + TeamUtils.parseAndShowMessage(data, view.errorMessage); + deferred.reject(); + }); + } else { + deferred.resolve(info); + } + } - if (info.memberOfCurrentTeam) { - info.alreadyMember = true; - info.memberOfCurrentTeam = true; - deferred.resolve(info); - } else { - if (teamHasSpace) { - var view = this; - $.ajax({ - type: 'GET', - url: view.teamMembershipsUrl, - data: {'username': username, 'course_id': view.courseID} - }).done(function (data) { - info.alreadyMember = (data.count > 0); - info.memberOfCurrentTeam = false; - info.teamHasSpace = teamHasSpace; - deferred.resolve(info); - }).fail(function (data) { - TeamUtils.parseAndShowMessage(data, view.errorMessage); - deferred.reject(); - }); - } else { - deferred.resolve(info); - } - } - - return deferred.promise(); - } - }); - }); + return deferred.promise(); + } + }); + }); }).call(this, define || RequireJS.define); diff --git a/lms/djangoapps/teams/static/teams/js/views/team_profile.js b/lms/djangoapps/teams/static/teams/js/views/team_profile.js index cd8a717dcc..8184283dec 100644 --- a/lms/djangoapps/teams/static/teams/js/views/team_profile.js +++ b/lms/djangoapps/teams/static/teams/js/views/team_profile.js @@ -16,7 +16,7 @@ 'click .leave-team-link': 'leaveTeam' }, initialize: function (options) { - this.listenTo(this.model, "change", this.render); + this.teamEvents = options.teamEvents; this.courseID = options.courseID; this.maxTeamSize = options.maxTeamSize; this.requestUsername = options.requestUsername; @@ -26,13 +26,13 @@ this.countries = TeamUtils.selectorOptionsArrayToHashWithBlank(options.countries); this.languages = TeamUtils.selectorOptionsArrayToHashWithBlank(options.languages); + this.listenTo(this.model, "change", this.render); }, render: function () { var memberships = this.model.get('membership'), discussionTopicID = this.model.get('discussion_topic_id'), isMember = TeamUtils.isUserMemberOfTeam(memberships, this.requestUsername); - this.$el.html(_.template(teamTemplate, { courseID: this.courseID, discussionTopicID: discussionTopicID, @@ -73,10 +73,16 @@ event.preventDefault(); var view = this; $.ajax({ - type: 'DELETE', - url: view.teamMembershipDetailUrl.replace('team_id', view.model.get('id')) + type: 'DELETE', + url: view.teamMembershipDetailUrl.replace('team_id', view.model.get('id')) }).done(function (data) { - view.model.fetch({}); + view.model.fetch() + .done(function() { + view.teamEvents.trigger('teams:update', { + action: 'leave', + team: view.model + }); + }); }).fail(function (data) { TeamUtils.parseAndShowMessage(data, view.errorMessage); }); diff --git a/lms/djangoapps/teams/static/teams/js/views/teams_tab.js b/lms/djangoapps/teams/static/teams/js/views/teams_tab.js index 4a2de47417..52d4830b7c 100644 --- a/lms/djangoapps/teams/static/teams/js/views/teams_tab.js +++ b/lms/djangoapps/teams/static/teams/js/views/teams_tab.js @@ -81,9 +81,13 @@ router.route.apply(router, route); }); + // Create an event queue to track team changes + this.teamEvents = _.clone(Backbone.Events); + this.teamMemberships = new TeamMembershipCollection( this.userInfo.team_memberships_data, { + teamEvents: this.teamEvents, url: this.teamMembershipsUrl, course_id: this.courseID, username: this.userInfo.username, @@ -94,6 +98,7 @@ this.myTeamsView = new MyTeamsView({ router: this.router, + teamEvents: this.teamEvents, collection: this.teamMemberships, teamMemberships: this.teamMemberships, maxTeamSize: this.maxTeamSize, @@ -107,12 +112,18 @@ this.topicsCollection = new TopicCollection( this.topics, - {url: options.topicsUrl, course_id: this.courseID, parse: true} + { + teamEvents: this.teamEvents, + url: options.topicsUrl, + course_id: this.courseID, + parse: true + } ).bootstrap(); this.topicsView = new TopicsView({ - collection: this.topicsCollection, - router: this.router + router: this.router, + teamEvents: this.teamEvents, + collection: this.topicsCollection }); this.mainView = this.tabbedView = new ViewWithHeader({ @@ -196,6 +207,7 @@ }) }), main: new TeamEditView({ + teamEvents: self.teamEvents, tagName: 'create-new-team', teamParams: teamsView.main.teamParams, primaryButtonTitle: 'Create' @@ -220,6 +232,7 @@ this.getTopic(topicID) .done(function(topic) { var collection = new TeamCollection([], { + teamEvents: self.teamEvents, course_id: self.courseID, topic_id: topicID, url: self.teamsUrl, @@ -229,7 +242,7 @@ collection.goTo(1) .done(function() { var teamsView = new TopicTeamsView({ - router: router, + router: self.router, topic: topic, collection: collection, teamMemberships: self.teamMemberships, @@ -278,25 +291,26 @@ self.getTopic(topicID).done(function(topic) { self.getTeam(teamID, true).done(function(team) { var view = new TeamProfileView({ + teamEvents: self.teamEvents, + router: self.router, + courseID: courseID, + model: team, + maxTeamSize: self.maxTeamSize, + isPrivileged: self.userInfo.privileged, + requestUsername: self.userInfo.username, + countries: self.countries, + languages: self.languages, + teamMembershipDetailUrl: self.teamMembershipDetailUrl + }); + var teamJoinView = new TeamJoinView({ + teamEvents: self.teamEvents, courseID: courseID, - model: team, - maxTeamSize: self.maxTeamSize, - isPrivileged: self.userInfo.privileged, - requestUsername: self.userInfo.username, - countries: self.countries, - languages: self.languages, - teamMembershipDetailUrl: self.teamMembershipDetailUrl - }); - var teamJoinView = new TeamJoinView( - { - courseID: courseID, - model: team, - teamsUrl: self.teamsUrl, - maxTeamSize: self.maxTeamSize, - currentUsername: self.userInfo.username, - teamMembershipsUrl: self.teamMembershipsUrl - } - ); + model: team, + teamsUrl: self.teamsUrl, + maxTeamSize: self.maxTeamSize, + currentUsername: self.userInfo.username, + teamMembershipsUrl: self.teamMembershipsUrl + }); deferred.resolve( self.createViewWithHeader( { diff --git a/lms/djangoapps/teams/static/teams/js/views/topic_teams.js b/lms/djangoapps/teams/static/teams/js/views/topic_teams.js index 62428b7c24..da8b670fc7 100644 --- a/lms/djangoapps/teams/static/teams/js/views/topic_teams.js +++ b/lms/djangoapps/teams/static/teams/js/views/topic_teams.js @@ -17,20 +17,26 @@ }, render: function() { - TeamsView.prototype.render.call(this); + var self = this; + $.when( + this.collection.refresh(), + this.teamMemberships.refresh() + ).done(function() { + TeamsView.prototype.render.call(self); - if (this.teamMemberships.canUserCreateTeam()) { - var message = interpolate_text( - _.escape(gettext("Try {browse_span_start}browsing all teams{span_end} or {search_span_start}searching team descriptions{span_end}. If you still can't find a team to join, {create_span_start}create a new team in this topic{span_end}.")), - { - 'browse_span_start': '', - 'search_span_start': '', - 'create_span_start': '', - 'span_end': '' - } - ); - this.$el.append(_.template(teamActionsTemplate, {message: message})); - } + if (self.teamMemberships.canUserCreateTeam()) { + var message = interpolate_text( + _.escape(gettext("Try {browse_span_start}browsing all teams{span_end} or {search_span_start}searching team descriptions{span_end}. If you still can't find a team to join, {create_span_start}create a new team in this topic{span_end}.")), + { + 'browse_span_start': '', + 'search_span_start': '', + 'create_span_start': '', + 'span_end': '' + } + ); + self.$el.append(_.template(teamActionsTemplate, {message: message})); + } + }); return this; }, diff --git a/lms/djangoapps/teams/static/teams/js/views/topics.js b/lms/djangoapps/teams/static/teams/js/views/topics.js index 7217e42a36..b1b4df19bb 100644 --- a/lms/djangoapps/teams/static/teams/js/views/topics.js +++ b/lms/djangoapps/teams/static/teams/js/views/topics.js @@ -1,9 +1,10 @@ ;(function (define) { 'use strict'; define([ + 'gettext', 'teams/js/views/topic_card', 'common/js/components/views/paginated_view' - ], function (TopicCardView, PaginatedView) { + ], function (gettext, TopicCardView, PaginatedView) { var TopicsView = PaginatedView.extend({ type: 'topics', @@ -18,6 +19,16 @@ srInfo: this.srInfo }); PaginatedView.prototype.initialize.call(this); + }, + + render: function() { + var self = this; + this.collection.refresh() + .done(function() { + self.collection.isStale = false; + PaginatedView.prototype.render.call(self); + }); + return this; } }); return TopicsView;