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

Learner dashboard 3.2 #3759

Merged
merged 71 commits into from Aug 28, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
f7af522
Init work.
arunabh98 Jul 26, 2017
2e6a78d
Learner dashboard milestone 3.1
arunabh98 Jul 26, 2017
58bf6b3
Fix lint errors.
arunabh98 Jul 26, 2017
ab3adf9
Add tests.
arunabh98 Jul 26, 2017
af9c34c
Partially address review comments.
arunabh98 Jul 29, 2017
bb5692c
Combine handlers.
arunabh98 Jul 30, 2017
d0526be
Add tests.
arunabh98 Jul 30, 2017
747d7ec
Remove the old handlers.
arunabh98 Jul 30, 2017
24b58a6
Fix function name.
arunabh98 Jul 30, 2017
20534ab
Address review comments 2.
arunabh98 Aug 2, 2017
98eba4c
Remove redundant code.
arunabh98 Aug 2, 2017
82819c2
Address another review comment.
arunabh98 Aug 2, 2017
d74947d
Fix nerge conflicts.
arunabh98 Aug 2, 2017
6a044ea
Add play later to option.
arunabh98 Aug 3, 2017
1861d4c
Add play later icon.
arunabh98 Aug 3, 2017
eeeeab2
Merge branch 'learner-dashboard-sixth-milestone' into learner-dashboa…
arunabh98 Aug 3, 2017
3aaade0
Add learner dashboard icons to library.
arunabh98 Aug 5, 2017
26dca72
Add remove modal.
arunabh98 Aug 12, 2017
6e37110
Add playlist to dashboard.
arunabh98 Aug 13, 2017
55d0131
Fix merge conflicts.
arunabh98 Aug 13, 2017
ac24e6d
Add backend feedback.
arunabh98 Aug 15, 2017
35506ca
Remove unncessary code.
arunabh98 Aug 15, 2017
e792b12
Fix rights manager.
arunabh98 Aug 15, 2017
8e02036
Merge remote-tracking branch 'upstream/develop' into learner-dashboar…
arunabh98 Aug 15, 2017
1f9287e
Add list.
arunabh98 Aug 15, 2017
08c77d4
Fix big in sortable list.
arunabh98 Aug 15, 2017
3a2669c
Further progress.
arunabh98 Aug 17, 2017
8baaeab
Fix part of e2e test.
arunabh98 Aug 17, 2017
84e1588
Fix lint errors.
arunabh98 Aug 17, 2017
0fa0688
Add new line.
arunabh98 Aug 17, 2017
004900e
Remove newline.
arunabh98 Aug 17, 2017
9b507b0
Remove unnecessary changes.
arunabh98 Aug 17, 2017
dc2f6f7
Add new line.
arunabh98 Aug 17, 2017
95be238
Fix rights manager.
arunabh98 Aug 17, 2017
fe3dc66
Streamline exploration tile.
arunabh98 Aug 17, 2017
4e77eb6
Add collections and search to playlist.
arunabh98 Aug 17, 2017
c16db90
Fix lint errors.
arunabh98 Aug 17, 2017
b51066c
Fix more lint errors.
arunabh98 Aug 17, 2017
577544a
Fix errors.
arunabh98 Aug 17, 2017
c50e398
Fix lint errors.
arunabh98 Aug 17, 2017
5a5c5e7
Address review comments.
arunabh98 Aug 19, 2017
e349e45
Address review comments.
arunabh98 Aug 20, 2017
dfce5d3
Same for collections.
arunabh98 Aug 20, 2017
c96d704
Address more review comments.
arunabh98 Aug 21, 2017
924268d
Address all review comments.
arunabh98 Aug 23, 2017
3f866f0
Fix lint errors.
arunabh98 Aug 23, 2017
0a2c049
Add e2e test for plurals.
arunabh98 Aug 24, 2017
881d846
Address review comments 2.
arunabh98 Aug 25, 2017
43ac635
Add hindi translations.
arunabh98 Aug 25, 2017
6fa3718
Partially address review comments.
arunabh98 Aug 25, 2017
7d96b5c
Address more review comments.
arunabh98 Aug 25, 2017
45a4cb3
Add domain object.
arunabh98 Aug 25, 2017
f5c8882
Add service.
arunabh98 Aug 25, 2017
4c63a1c
Fix lint errors.
arunabh98 Aug 25, 2017
2dd1286
Fix a bug.
arunabh98 Aug 25, 2017
ada0a9d
Fix lint errors.
arunabh98 Aug 25, 2017
aff0b0c
Add directive for icons.
arunabh98 Aug 26, 2017
aea81d2
Fix lint errors.
arunabh98 Aug 26, 2017
2667e96
Fix more lint errors.
arunabh98 Aug 26, 2017
883b938
Remove unnecessary code.
arunabh98 Aug 26, 2017
2f0fcfc
Remove unnecessary code 2.
arunabh98 Aug 26, 2017
43d193e
Address review comments 3.
arunabh98 Aug 26, 2017
5523dbe
Fix e2e tests.
arunabh98 Aug 27, 2017
a4b64b8
Remve unintended changes.
arunabh98 Aug 27, 2017
fec579a
Address review comments 4.
arunabh98 Aug 27, 2017
e0d7e7d
Fix lint errors.
arunabh98 Aug 27, 2017
c53fc5b
Fix more lint errors.
arunabh98 Aug 27, 2017
6897721
Merge remote-tracking branch 'upstream/develop' into learner-dashboar…
arunabh98 Aug 27, 2017
921c586
Changed another translation file to account for the new keys.
arunabh98 Aug 27, 2017
1299523
Address review comments 4
arunabh98 Aug 27, 2017
ae86749
Address review comments 5.
arunabh98 Aug 28, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 6 additions & 7 deletions core/domain/learner_progress_services.py
Expand Up @@ -960,10 +960,10 @@ def get_activity_progress(user_id):
user_id: str. The id of the learner.

Returns:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like I shouldn't have to comment on this in three separate passes, but there are still three return values here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

LearnerProgress. The learner progress domain object corresponding to the
particular learner.
dict. The numbers of the activities that are no longer present. It
contains four keys:
(LearnerProgress, dict, list(str)). The first return value is the
learner progress domain object corresponding to the particular
learner. The second return value is the numbers of the activities
that are no longer present. It contains four keys:
- incomplete_explorations: int. The number of incomplete
explorations no longer present.
- incomplete_collections: int. The number of incomplete collections
Expand All @@ -972,9 +972,8 @@ def get_activity_progress(user_id):
no longer present.
- completed_collections: int. The number of completed collections no
longer present.
list(str). The titles of the collections to which new explorations have
been added.

The third return valus is the titles of the collections to which new
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

valus --> value

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

explorations have been added.
"""
activity_ids_in_learner_dashboard = (
get_learner_dashboard_activities(user_id))
Expand Down
Expand Up @@ -35,7 +35,7 @@ oppia.directive('collectionSummaryTile', [
getThumbnailBgColor: '&thumbnailBgColor',
isLinkedToEditorPage: '=?isLinkedToEditorPage',
getCategory: '&category',
isPlaylistMode: '&playlistMode',
isPlaylistTile: '&playlistTile',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want the actual directive attr name to also be is-playlist-tile, otherwise it's as though it's naming the playlist tile that's being passed in.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

showLearnerDashboardIconsIfPossible: (
'&showLearnerDashboardIconsIfPossible')
},
Expand All @@ -44,9 +44,9 @@ oppia.directive('collectionSummaryTile', [
'collection_summary_tile_directive.html'),
controller: [
'$scope', 'oppiaDatetimeFormatter',
'COLLECTION_VIEWER_URL', 'COLLECTION_EDITOR_URL', function($scope,
oppiaDatetimeFormatter, COLLECTION_VIEWER_URL,
COLLECTION_EDITOR_URL) {
'COLLECTION_VIEWER_URL', 'COLLECTION_EDITOR_URL', function(
$scope, oppiaDatetimeFormatter,
COLLECTION_VIEWER_URL, COLLECTION_EDITOR_URL) {
$scope.userIsLoggedIn = GLOBALS.userIsLoggedIn;
$scope.DEFAULT_EMPTY_TITLE = 'Untitled';
$scope.ACTIVITY_TYPE_COLLECTION = constants.ACTIVITY_TYPE_COLLECTION;
Expand Down Expand Up @@ -76,9 +76,8 @@ oppia.directive('collectionSummaryTile', [
return UrlInterpolationService.getStaticImageUrl(url);
};

$scope.collectionIsActive = false;
$scope.toggleCollectionIsActive = function() {
$scope.collectionIsActive = !$scope.collectionIsActive;
$scope.setHoverState = function(hoverState) {
$scope.collectionIsCurrentlyHoveredOver = hoverState;
};
}
]
Expand Down
Expand Up @@ -44,7 +44,7 @@ oppia.directive('explorationSummaryTile', [
// if it is not specified, it is treated as 0, which means that the
// desktop version of the summary tile is always displayed.
mobileCutoffPx: '@mobileCutoffPx',
isPlaylistMode: '&playlistMode',
isPlaylistTile: '&playlistTile',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

showLearnerDashboardIconsIfPossible: (
'&showLearnerDashboardIconsIfPossible')
},
Expand Down Expand Up @@ -118,9 +118,8 @@ oppia.directive('explorationSummaryTile', [

$scope.MAX_AVATARS_TO_DISPLAY = 5;

$scope.explorationIsActive = false;
$scope.toggleExplorationIsActive = function() {
$scope.explorationIsActive = !$scope.explorationIsActive;
$scope.setHoverState = function(hoverState) {
$scope.explorationIsCurrentlyHoveredOver = hoverState;
};

$scope.getAverageRating = function() {
Expand Down
Expand Up @@ -2,20 +2,20 @@
activity-type="ACTIVITY_TYPE_COLLECTION"
activity-id="getCollectionId()"
activity-title="getCollectionTitle()"
activity-active="collectionIsActive">
activity-active="collectionIsCurrentlyHoveredOver">
</learner-dashboard-icons>
<md-card class="oppia-activity-summary-tile"
ng-class="{'oppia-activity-playlist-tile': isPlaylistMode()}"
ng-mouseenter="toggleCollectionIsActive()" ng-mouseleave="toggleCollectionIsActive()"
ng-class="{'oppia-activity-playlist-tile': isPlaylistTile()}"
ng-mouseenter="setHoverState(true)" ng-mouseleave="setHoverState(false)"
style="position: relative; z-index: 5;">
<a ng-href="<[getCollectionLink()]>" style="text-decoration: none;">
<div class="title-section" style="background-color: <[getThumbnailBgColor()]>;">
<img class="collection-corner-image" ng-src="<[getStaticImageUrl('/general/collection_corner.svg')]>" alt="">
<img class="thumbnail-image" ng-src="<[getCompleteThumbnailIconUrl()]>" alt="<[getCategory()]>" ng-style="isPlaylistMode() && {'top': '6px', 'width': '60px'}">
<h3 class="activity-title protractor-test-collection-summary-tile-title" ng-style="isPlaylistMode() && {'width': '93%', 'text-align': 'center'}"><[getCollectionTitle() || DEFAULT_EMPTY_TITLE]></h3>
<img class="thumbnail-image" ng-src="<[getCompleteThumbnailIconUrl()]>" alt="<[getCategory()]>" ng-style="isPlaylistTile() && {'top': '6px', 'width': '60px'}">
<h3 class="activity-title protractor-test-collection-summary-tile-title" ng-style="isPlaylistTile() && {'width': '93%', 'text-align': 'center'}"><[getCollectionTitle() || DEFAULT_EMPTY_TITLE]></h3>
</div>

<div ng-style="isPlaylistMode() && {'float': 'right', 'width': '67%', 'margin-top': '3%'}">
<div ng-style="isPlaylistTile() && {'float': 'right', 'width': '67%', 'margin-top': '3%'}">
<div class="objective">
<[getObjective() | truncateAndCapitalize: 95]>
<span ng-if="!getObjective()">No objective specified.</span>
Expand All @@ -34,7 +34,7 @@ <h3 class="activity-title protractor-test-collection-summary-tile-title" ng-styl
</li>
</ul>
</div>
<div ng-if="!isPlaylistMode()" class="title-section-mask"></div>
<div ng-if="!isPlaylistTile()" class="title-section-mask"></div>
</a>
</md-card>

Expand Down
Expand Up @@ -2,15 +2,15 @@
activity-type="ACTIVITY_TYPE_EXPLORATION"
activity-id="getExplorationId()"
activity-title="getExplorationTitle()"
activity-active="explorationIsActive">
activity-active="explorationIsCurrentlyHoveredOver">
</learner-dashboard-icons>
<md-card ng-class="[isCollectionPreviewTile ? 'oppia-activity-summary-tile-mobile' : 'oppia-activity-summary-tile', {'small-width': !isWindowLarge}, {'oppia-activity-playlist-tile': isPlaylistMode()}]"
ng-mouseenter="toggleExplorationIsActive()" ng-mouseleave="toggleExplorationIsActive()"
<md-card ng-class="[isCollectionPreviewTile ? 'oppia-activity-summary-tile-mobile' : 'oppia-activity-summary-tile', {'small-width': !isWindowLarge}, {'oppia-activity-playlist-tile': isPlaylistTile()}]"
ng-mouseenter="setHoverState(true)" ng-mouseleave="setHoverState(false)"
style="position: relative; z-index: 5;">
<a ng-href="<[getExplorationLink()]>" target="<[openInNewWindow ? '_blank' : '_self']>">
<div class="title-section" style="background-color: <[getThumbnailBgColor()]>;">
<img class="thumbnail-image" ng-src="<[getCompleteThumbnailIconUrl()]>" alt="<[getCategory()]>" ng-style="isPlaylistMode() && {'top': '4px', 'width': '50px'}">
<h3 class="activity-title protractor-test-exp-summary-tile-title" ng-style="isPlaylistMode() && {'width': '93%'}">
<img class="thumbnail-image" ng-src="<[getCompleteThumbnailIconUrl()]>" alt="<[getCategory()]>" ng-style="isPlaylistTile() && {'top': '4px', 'width': '50px'}">
<h3 class="activity-title protractor-test-exp-summary-tile-title" ng-style="isPlaylistTile() && {'width': '93%'}">
<span ng-if="isWindowLarge"><[getExplorationTitle()|truncate:40]></span>
<span ng-if="!isWindowLarge"><[getExplorationTitle()|truncate:40]></span>
</h3>
Expand All @@ -27,7 +27,7 @@ <h3 class="activity-title protractor-test-exp-summary-tile-title" ng-style="isPl
</div>
</div>
</div>
<div ng-if="!isPlaylistMode()" class="title-section-mask"></div>
<div ng-if="!isPlaylistTile()" class="title-section-mask"></div>
<div ng-attr-section="<[isWindowLarge ? undefined : 'right-section']>" class="summary-section">
<div ng-if="isWindowLarge" class="objective protractor-test-exp-summary-tile-objective">
<[getObjective() | truncateAndCapitalize: 95]>
Expand Down
Expand Up @@ -49,7 +49,7 @@ describe('Feedback message object factory', function() {
created_on: 1000
};

feedbackMessageSummary = (
var feedbackMessageSummary = (
FeedbackMessageSummaryObjectFactory.createFromBackendDict(
messageSummary));

Expand Down
Expand Up @@ -40,7 +40,61 @@ oppia.factory('LearnerDashboardActivityIdsObjectFactory', [function() {
this.explorationPlaylistIds.indexOf(activityId) !== -1) {
return true;
} else {
false;
return false;
}
});

LearnerDashboardActivityIds.prototype.belongsToExplorationPlaylist = (
function(explorationId) {
if (this.explorationPlaylistIds.indexOf(explorationId) !== -1) {
return true;
} else {
return false;
}
});

LearnerDashboardActivityIds.prototype.belongsToCollectionPlaylist = (
function(collectionId) {
if (this.collectionPlaylistIds.indexOf(collectionId) !== -1) {
return true;
} else {
return false;
}
});

LearnerDashboardActivityIds.prototype.belongsToCompletedExplorations = (
function(explorationId) {
if (this.completedExplorationIds.indexOf(explorationId) !== -1) {
return true;
} else {
return false;
}
});

LearnerDashboardActivityIds.prototype.belongsToCompletedCollections = (
function(collectionId) {
if (this.completedCollectionIds.indexOf(collectionId) !== -1) {
return true;
} else {
return false;
}
});

LearnerDashboardActivityIds.prototype.belongsToIncompleteExplorations = (
function(explorationId) {
if (this.incompleteExplorationIds.indexOf(explorationId) !== -1) {
return true;
} else {
return false;
}
});

LearnerDashboardActivityIds.prototype.belongsToIncompleteCollections = (
function(collectionId) {
if (this.incompleteCollectionIds.indexOf(collectionId) !== -1) {
return true;
} else {
return false;
}
});

Expand Down
@@ -0,0 +1,138 @@
// Copyright 2016 The Oppia Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
* @fileoverview Tests for LearnerDashboardActivityIdsObjectFactory.
*/

describe('Learner dashboard activity ids object factory', function() {
var LearnerDashboardActivityIdsObjectFactory = null;

beforeEach(module('oppia'));

beforeEach(inject(function($injector) {
LearnerDashboardActivityIdsObjectFactory = $injector.get(
'LearnerDashboardActivityIdsObjectFactory');
}));

var learnerDashboardActivityIdsDict = {
incomplete_exploration_ids: ['0', '1'],
incomplete_collection_ids: ['2', '3'],
completed_exploration_ids: ['4', '5'],
completed_collection_ids: ['6', '7'],
exploration_playlist_ids: ['8', '9'],
collection_playlist_ids: ['10', '11']
};

it('should check if activity id is present among learner dashboard ' +
' activity ids', function() {
var learnerDashboardActivityIds = (
LearnerDashboardActivityIdsObjectFactory.createFromBackendDict(
learnerDashboardActivityIdsDict));

expect(learnerDashboardActivityIds.includesActivity('0')).toEqual(true);
expect(learnerDashboardActivityIds.includesActivity('1')).toEqual(true);
expect(learnerDashboardActivityIds.includesActivity('8')).toEqual(true);

expect(learnerDashboardActivityIds.includesActivity('12')).toEqual(false);
expect(learnerDashboardActivityIds.includesActivity('13')).toEqual(false);
expect(learnerDashboardActivityIds.includesActivity('14')).toEqual(false);
});


it('should add exploration to learner playlist', function() {
var learnerDashboardActivityIds = (
LearnerDashboardActivityIdsObjectFactory.createFromBackendDict(
learnerDashboardActivityIdsDict));

learnerDashboardActivityIds.addToExplorationLearnerPlaylist('12');
expect(learnerDashboardActivityIds.explorationPlaylistIds).toEqual(
['8', '9', '12']);

learnerDashboardActivityIds.addToExplorationLearnerPlaylist('13');
expect(learnerDashboardActivityIds.explorationPlaylistIds).toEqual(
['8', '9', '12', '13']);
});

it('should add collection to learner playlist', function() {
var learnerDashboardActivityIds = (
LearnerDashboardActivityIdsObjectFactory.createFromBackendDict(
learnerDashboardActivityIdsDict));

learnerDashboardActivityIds.addToCollectionLearnerPlaylist('12');
expect(learnerDashboardActivityIds.collectionPlaylistIds).toEqual(
['10', '11', '12']);

learnerDashboardActivityIds.addToCollectionLearnerPlaylist('13');
expect(learnerDashboardActivityIds.collectionPlaylistIds).toEqual(
['10', '11', '12', '13']);
});

it('should remove exploration from learner playlist', function() {
var learnerDashboardActivityIds = (
LearnerDashboardActivityIdsObjectFactory.createFromBackendDict(
learnerDashboardActivityIdsDict));

learnerDashboardActivityIds.removeFromExplorationLearnerPlaylist('9');
expect(learnerDashboardActivityIds.explorationPlaylistIds).toEqual(
['8', '12', '13']);

learnerDashboardActivityIds.removeFromExplorationLearnerPlaylist('8');
expect(learnerDashboardActivityIds.explorationPlaylistIds).toEqual(
['12', '13']);
});

it('should remove collection from learner playlist', function() {
var learnerDashboardActivityIds = (
LearnerDashboardActivityIdsObjectFactory.createFromBackendDict(
learnerDashboardActivityIdsDict));

learnerDashboardActivityIds.removeFromCollectionLearnerPlaylist('11');
expect(learnerDashboardActivityIds.collectionPlaylistIds).toEqual(
['10', '12', '13']);

learnerDashboardActivityIds.removeFromCollectionLearnerPlaylist('10');
expect(learnerDashboardActivityIds.collectionPlaylistIds).toEqual(
['12', '13']);
});

it('should fetch the learner dashboard activity ids domain object from the ' +
' backend summary dict', function() {
var learnerDashboardActivityIdsDict = {
incomplete_exploration_ids: ['0', '1'],
incomplete_collection_ids: ['2', '3'],
completed_exploration_ids: ['4', '5'],
completed_collection_ids: ['6', '7'],
exploration_playlist_ids: ['8', '9'],
collection_playlist_ids: ['10', '11']
};

var learnerDashboardActivityIds = (
LearnerDashboardActivityIdsObjectFactory.createFromBackendDict(
learnerDashboardActivityIdsDict));

expect(learnerDashboardActivityIds.incompleteExplorationIds).toEqual(
['0', '1']);
expect(learnerDashboardActivityIds.incompleteCollectionIds).toEqual(
['2', '3']);
expect(learnerDashboardActivityIds.completedExplorationIds).toEqual(
['4', '5']);
expect(learnerDashboardActivityIds.completedCollectionIds).toEqual(
['6', '7']);
expect(learnerDashboardActivityIds.explorationPlaylistIds).toEqual(
['8', '9']);
expect(learnerDashboardActivityIds.collectionPlaylistIds).toEqual(
['10', '11']);
});
});