Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-analytics-dashboard
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-analytics-dashboard
Commits
2120af6a
Commit
2120af6a
authored
Feb 01, 2017
by
Dennis Jen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
WIP: adding filters to course list
* Refactored filter into checkbox and drop down filters
parent
d531db73
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
197 additions
and
135 deletions
+197
-135
analytics_dashboard/static/apps/components/filter/templates/checkbox-filter.underscore
+12
-0
analytics_dashboard/static/apps/components/filter/templates/drop-down-filter.underscore
+12
-26
analytics_dashboard/static/apps/components/filter/views/checkbox-filter.js
+50
-0
analytics_dashboard/static/apps/components/filter/views/drop-down-filter.js
+63
-0
analytics_dashboard/static/apps/components/filter/views/filter.js
+34
-87
analytics_dashboard/static/apps/course-list/list/views/course-list.js
+3
-1
analytics_dashboard/static/apps/learners/roster/views/controls.js
+20
-20
analytics_dashboard/static/apps/learners/roster/views/roster.js
+3
-1
No files found.
analytics_dashboard/static/apps/components/filter/templates/checkbox-filter.underscore
0 → 100644
View file @
2120af6a
<% if (!_.isEmpty(filterValues)) { %>
<% var filterId = 'filter-' + filterKey; %>
<hr>
<div id="<%- filterId %>">
<% _.each(filterValues, function (filterValue) { %>
<% if (filterValue.name === 'inactive') { %>
<input id="<%- filterValue.name %>" type="checkbox" value="<%- filterValue.name %>" <% if (isChecked) { %> checked <% } %>>
<label for="<%- filterValue.name %>"> <%- selectDisplayName %> </label><br>
<% } %>
<% }); %>
</div>
<% } %>
analytics_dashboard/static/apps/
learners/roster/templates/
filter.underscore
→
analytics_dashboard/static/apps/
components/filter/templates/drop-down-
filter.underscore
View file @
2120af6a
<% if (!_.isEmpty(filterValues)) { %>
<% var filterId = 'filter-' + filterKey; %>
<hr>
<% if (!(filterKey === 'ignore_segments')) { %>
<label for="<%- filterId %>">
<%- selectDisplayName %>
</label>
<select id="<%- filterId %>" class="form-control">
<% _.each(filterValues, function (filterValue) { %>
<option value="<%- filterValue.name %>" <% if (filterValue.selected) { %> selected <% } %>>
<%- filterValue.displayName %>
</option>
<% }); %>
</select>
<% } %>
<% if (filterKey === 'ignore_segments') { %>
<div id="<%- filterId %>">
<% _.each(filterValues, function (filterValue) { %>
<% if (filterValue.name === 'inactive') { %>
<input id="<%- filterValue.name %>" type="checkbox" value="<%- filterValue.name %>" <% if (hideInactive) { %> checked <% } %>>
<label for="<%- filterValue.name %>"> <%- selectDisplayName %> </label><br>
<% } %>
<% }); %>
</div>
<% } %>
<% var filterId = 'filter-' + filterKey; %>
<hr>
<label for="<%- filterId %>">
<%- selectDisplayName %>
</label>
<select id="<%- filterId %>" class="form-control">
<% _.each(filterValues, function (filterValue) { %>
<option value="<%- filterValue.name %>" <% if (filterValue.selected) { %> selected <% } %>>
<%- filterValue.displayName %>
</option>
<% }); %>
</select>
<% } %>
analytics_dashboard/static/apps/components/filter/views/checkbox-filter.js
0 → 100644
View file @
2120af6a
/**
/**
* Extends the filter view for checkbox filters.
*/
define
(
function
(
require
)
{
'use strict'
;
var
$
=
require
(
'jquery'
),
_
=
require
(
'underscore'
),
filterTemplate
=
require
(
'text!components/filter/templates/checkbox-filter.underscore'
),
Filter
=
require
(
'components/filter/views/filter'
);
return
Filter
.
extend
({
template
:
_
.
template
(
filterTemplate
),
/**
* Returns the default template options along with the checkbox state.
*/
templateHelpers
:
function
()
{
var
templateOptions
=
Filter
.
prototype
.
templateHelpers
.
call
(
this
);
if
(
this
.
options
.
filterKey
in
this
.
options
.
collection
.
getActiveFilterFields
())
{
templateOptions
.
isChecked
=
true
;
}
else
{
templateOptions
.
isChecked
=
false
;
}
return
templateOptions
;
},
onFilter
:
function
(
event
)
{
var
$inputs
=
$
(
event
.
currentTarget
).
find
(
'input:checkbox:checked'
),
filterKey
=
$
(
event
.
currentTarget
).
attr
(
'id'
).
slice
(
7
),
// chop off "filter-" prefix
appliedFilters
=
[],
filterValue
=
''
;
if
(
$inputs
.
length
)
{
_
.
each
(
$inputs
,
_
.
bind
(
function
(
input
)
{
appliedFilters
.
push
(
$
(
input
).
attr
(
'id'
));
},
this
));
filterValue
=
appliedFilters
.
join
(
','
);
this
.
collection
.
setFilterField
(
filterKey
,
filterValue
);
}
else
{
this
.
collection
.
unsetFilterField
(
filterKey
);
}
this
.
filterUpdated
(
filterValue
);
}
});
});
analytics_dashboard/static/apps/components/filter/views/drop-down-filter.js
0 → 100644
View file @
2120af6a
/**
* Extends the filter view for drop down filters.
*/
define
(
function
(
require
)
{
'use strict'
;
var
$
=
require
(
'jquery'
),
_
=
require
(
'underscore'
),
filterTemplate
=
require
(
'text!components/filter/templates/drop-down-filter.underscore'
),
Filter
=
require
(
'components/filter/views/filter'
);
return
Filter
.
extend
({
template
:
_
.
template
(
filterTemplate
),
/**
* Returns the default template options along with an "All" option and the
* current selection state.
*/
templateHelpers
:
function
()
{
var
templateOptions
=
Filter
.
prototype
.
templateHelpers
.
call
(
this
),
filterValues
=
templateOptions
.
filterValues
,
selectedFilterValue
;
// update filter values with an "All" option and current selection
if
(
filterValues
.
length
>
0
)
{
filterValues
.
unshift
({
name
:
this
.
catchAllFilterValue
,
// Translators: "All" refers to viewing all items (e.g. all courses).
displayName
:
gettext
(
'All'
)
});
// Assumes that you can only filter by one filterKey at a time.
selectedFilterValue
=
_
.
chain
(
filterValues
)
.
pluck
(
'name'
)
.
intersection
(
this
.
options
.
collection
.
getActiveFilterFields
())
.
first
()
.
value
()
||
this
.
catchAllFilterValue
;
_
.
findWhere
(
filterValues
,
{
name
:
selectedFilterValue
}).
selected
=
true
;
}
return
templateOptions
;
},
onFilter
:
function
(
event
)
{
var
selectedOption
=
$
(
event
.
currentTarget
).
find
(
'option:selected'
),
selectedFilterValue
=
selectedOption
.
val
(),
filterWasUnset
=
selectedFilterValue
===
this
.
catchAllFilterValue
;
event
.
preventDefault
();
if
(
filterWasUnset
)
{
this
.
collection
.
unsetFilterField
(
this
.
options
.
filterKey
);
}
else
{
this
.
collection
.
setFilterField
(
this
.
options
.
filterKey
,
selectedFilterValue
);
}
this
.
filterUpdated
(
this
.
options
.
filterKey
);
}
});
return
Filter
;
});
analytics_dashboard/static/apps/
learners/ros
ter/views/filter.js
→
analytics_dashboard/static/apps/
components/fil
ter/views/filter.js
View file @
2120af6a
/**
* A view which renders a select box in order to filter a L
earners
Collection.
* A view which renders a select box in order to filter a L
ist
Collection.
*
* It takes a collection, a display name, a filter field, and a set of possible
* filter values.
...
...
@@ -12,7 +12,6 @@ define(function(require) {
Marionette
=
require
(
'marionette'
),
Utils
=
require
(
'utils/utils'
),
filterTemplate
=
require
(
'text!learners/roster/templates/filter.underscore'
),
Filter
;
...
...
@@ -27,34 +26,44 @@ define(function(require) {
// It is assumed that there can never be a filter with an empty
// name, therefore it's safe to use the empty string as a
// property in this object. The API interprets this as "all
//
learner
s, unfiltered".
//
item
s, unfiltered".
catchAllFilterValue
:
''
,
className
:
'learners-filter'
,
className
:
function
()
{
return
this
.
appClass
+
'-filter'
;
},
template
:
_
.
template
(
filterTemplate
),
/**
* Updates the filter set on the collection and calls filterUpdated().
*/
onFilter
:
function
()
{
throw
'onFilter must be implemented'
},
/**
* Initialize a filter.
*
* @param options an options object which must include the following
* key/values:
* - collection (L
earnersCollection): the learners
collection to
* - collection (L
istCollection): the
collection to
* filter.
* - filterKey (string): the field to be filtered by on the learner
* collection.
* - filterKey (string): the field to be filtered by on the collection.
* - filterValues (Object): the set of valid values that the
* filterKey can take on, represented as a mapping from
* filter values to the number of learners matching the applied
* filter.
* filter values to the number of items matching the applied filter.
* - selectDisplayName (string): a *translated* string that will
* appear as the label for this filter.
* - trackingModel (Object): tracking model for broadcasting filter
* events.
*/
initialize
:
function
(
options
)
{
this
.
options
=
options
||
{};
_
.
bind
(
this
.
onSelectFilter
,
this
);
this
.
options
=
_
.
defaults
({},
options
,
{
trackSubject
:
'list'
,
appClass
:
''
});
this
.
options
=
_
.
defaults
(
this
.
options
,
{
trackFilterEventName
:
[
'edx'
,
'bi'
,
this
.
options
.
trackSubject
,
'filtered'
].
join
(
'.'
)
});
this
.
listenTo
(
this
.
options
.
collection
,
'sync'
,
this
.
render
);
},
...
...
@@ -65,108 +74,46 @@ define(function(require) {
// 'displayName' is the user-facing representation of the filter
// which combines the filter with the number of users belonging to
// it.
var
hideInactive
=
false
,
filterValues
,
selectedFilterValue
;
var
filterValues
;
filterValues
=
_
.
chain
(
this
.
options
.
filterValues
)
.
pairs
()
.
map
(
function
(
filterPair
)
{
var
name
=
filterPair
[
0
],
numLearners
=
filterPair
[
1
];
count
=
filterPair
[
1
];
return
{
name
:
name
,
displayName
:
_
.
template
(
// eslint-disable-next-line max-len
// Translators: 'name' here refers to the name of the filter, while '
numLearners' refers to the number of learner
s belonging to that filter.
gettext
(
'<%= name %> (<%=
numLearners
%>)'
)
// Translators: 'name' here refers to the name of the filter, while '
count' refers to the number of item
s belonging to that filter.
gettext
(
'<%= name %> (<%=
count
%>)'
)
)({
name
:
name
,
numLearners
:
Utils
.
localizeNumber
(
numLearners
,
0
)
count
:
Utils
.
localizeNumber
(
count
,
0
)
})
};
})
.
sortBy
(
'name'
)
.
value
();
if
(
filterValues
.
length
&&
this
.
options
.
filterInput
===
'select'
)
{
filterValues
.
unshift
({
name
:
this
.
catchAllFilterValue
,
// Translators: "All" refers to viewing all the learners in a course.
displayName
:
gettext
(
'All'
)
});
// Assumes that you can only filter by one filterKey at a time.
selectedFilterValue
=
_
.
chain
(
filterValues
)
.
pluck
(
'name'
)
.
intersection
(
this
.
options
.
collection
.
getActiveFilterFields
())
.
first
()
.
value
()
||
this
.
catchAllFilterValue
;
_
.
findWhere
(
filterValues
,
{
name
:
selectedFilterValue
}).
selected
=
true
;
}
if
(
this
.
options
.
filterKey
===
'ignore_segments'
)
{
// Translators: inactive meaning that these learners have not interacted with the course recently.
this
.
options
.
selectDisplayName
=
gettext
(
'Hide Inactive Learners'
);
}
if
(
'ignore_segments'
in
this
.
options
.
collection
.
getActiveFilterFields
())
{
hideInactive
=
true
;
}
return
{
filterKey
:
this
.
options
.
filterKey
,
filterValues
:
filterValues
,
hideInactive
:
hideInactive
,
selectDisplayName
:
this
.
options
.
selectDisplayName
};
},
onCheckboxFilter
:
function
(
event
)
{
var
$inputs
=
$
(
event
.
currentTarget
).
find
(
'input:checkbox:checked'
),
filterKey
=
$
(
event
.
currentTarget
).
attr
(
'id'
).
slice
(
7
),
// chop off "filter-" prefix
appliedFilters
=
[],
filterValue
=
''
;
if
(
$inputs
.
length
)
{
_
.
each
(
$inputs
,
_
.
bind
(
function
(
input
)
{
appliedFilters
.
push
(
$
(
input
).
attr
(
'id'
));
},
this
));
filterValue
=
appliedFilters
.
join
(
','
);
this
.
collection
.
setFilterField
(
filterKey
,
filterValue
);
}
else
{
this
.
collection
.
unsetFilterField
(
filterKey
);
}
/**
* Refreshes collection, sets focus, and triggers tracking event.
*/
filterUpdated
:
function
(
filterValue
)
{
this
.
collection
.
refresh
();
$
(
'#
learner-app
-focusable'
).
focus
();
this
.
options
.
trackingModel
.
trigger
(
'segment:track'
,
'edx.bi.roster.filtered'
,
{
$
(
'#
'
+
this
.
appClass
+
'
-focusable'
).
focus
();
this
.
options
.
trackingModel
.
trigger
(
'segment:track'
,
this
.
options
.
trackFilterEventName
,
{
category
:
filterValue
});
},
onSelectFilter
:
function
(
event
)
{
// Sends a request to the server for the filtered learner list.
var
selectedOption
=
$
(
event
.
currentTarget
).
find
(
'option:selected'
),
selectedFilterValue
=
selectedOption
.
val
(),
filterWasUnset
=
selectedFilterValue
===
this
.
catchAllFilterValue
;
event
.
preventDefault
();
if
(
this
.
options
.
filterKey
===
'segments'
)
{
selectedFilterValue
=
'inactive'
;
}
if
(
filterWasUnset
)
{
this
.
collection
.
unsetFilterField
(
this
.
options
.
filterKey
);
}
else
{
this
.
collection
.
setFilterField
(
this
.
options
.
filterKey
,
selectedFilterValue
);
}
this
.
collection
.
refresh
();
$
(
'#learner-app-focusable'
).
focus
();
this
.
options
.
trackingModel
.
trigger
(
'segment:track'
,
'edx.bi.roster.filtered'
,
{
category
:
this
.
options
.
filterKey
});
},
onFilter
:
function
(
event
)
{
if
(
$
(
event
.
currentTarget
).
find
(
'option'
).
length
)
{
this
.
onSelectFilter
(
event
);
}
else
if
(
$
(
event
.
currentTarget
).
find
(
'input:checkbox'
).
length
)
{
this
.
onCheckboxFilter
(
event
);
}
}
});
return
Filter
;
...
...
analytics_dashboard/static/apps/course-list/list/views/course-list.js
View file @
2120af6a
...
...
@@ -51,7 +51,9 @@ define(function(require) {
class
:
CourseListControlsView
,
options
:
{
collection
:
this
.
options
.
collection
,
trackingModel
:
this
.
options
.
trackingModel
trackingModel
:
this
.
options
.
trackingModel
,
trackSubject
:
this
.
options
.
trackSubject
,
appClass
:
this
.
options
.
appClass
}
},
{
...
...
analytics_dashboard/static/apps/learners/roster/views/controls.js
View file @
2120af6a
...
...
@@ -7,7 +7,8 @@ define(function(require) {
var
_
=
require
(
'underscore'
),
ParentView
=
require
(
'components/generic-list/common/views/parent-view'
),
LearnerFilter
=
require
(
'learners/roster/views/filter'
),
CheckboxFilter
=
require
(
'components/filter/views/checkbox-filter'
),
DropDownFilter
=
require
(
'components/filter/views/drop-down-filter'
),
LearnerSearch
=
require
(
'learners/roster/views/search'
),
rosterControlsTemplate
=
require
(
'text!learners/roster/templates/controls.underscore'
),
...
...
@@ -24,8 +25,16 @@ define(function(require) {
},
initialize
:
function
(
options
)
{
var
defaultFilterOptions
;
this
.
options
=
options
||
{};
defaultFilterOptions
=
{
collection
:
this
.
options
.
collection
,
trackingModel
:
this
.
options
.
trackingModel
,
trackSubject
:
this
.
options
.
trackSubject
,
appClass
:
this
.
options
.
appClass
};
this
.
childViews
=
[
{
region
:
'search'
,
...
...
@@ -39,41 +48,32 @@ define(function(require) {
},
{
region
:
'cohortFilter'
,
class
:
LearnerFilter
,
options
:
{
collection
:
this
.
options
.
collection
,
class
:
DropDownFilter
,
options
:
_
({
filterKey
:
'cohort'
,
filterValues
:
this
.
options
.
courseMetadata
.
get
(
'cohorts'
),
filterInput
:
'select'
,
selectDisplayName
:
gettext
(
'Cohort Groups'
),
trackingModel
:
this
.
options
.
trackingModel
}
}).
extend
(
defaultFilterOptions
)
},
{
region
:
'enrollmentTrackFilter'
,
class
:
LearnerFilter
,
options
:
{
collection
:
this
.
options
.
collection
,
class
:
DropDownFilter
,
options
:
_
({
filterKey
:
'enrollment_mode'
,
filterValues
:
this
.
options
.
courseMetadata
.
get
(
'enrollment_modes'
),
filterInput
:
'select'
,
selectDisplayName
:
gettext
(
'Enrollment Tracks'
),
trackingModel
:
this
.
options
.
trackingModel
}
selectDisplayName
:
gettext
(
'Enrollment Tracks'
)
}).
extend
(
defaultFilterOptions
)
},
{
region
:
'activeFilter'
,
class
:
LearnerFilter
,
options
:
{
collection
:
this
.
options
.
collection
,
class
:
CheckboxFilter
,
options
:
_
({
filterKey
:
'ignore_segments'
,
filterValues
:
this
.
options
.
courseMetadata
.
get
(
'segments'
),
filterInput
:
'checkbox'
,
// Translators: inactive meaning that these learners have not interacted with the course
// recently.
selectDisplayName
:
gettext
(
'Hide Inactive Learners'
),
trackingModel
:
this
.
options
.
trackingModel
}
}).
extend
(
defaultFilterOptions
)
}
];
}
...
...
analytics_dashboard/static/apps/learners/roster/views/roster.js
View file @
2120af6a
...
...
@@ -66,7 +66,9 @@ define(function(require) {
options
:
{
collection
:
this
.
options
.
collection
,
courseMetadata
:
this
.
options
.
courseMetadata
,
trackingModel
:
this
.
options
.
trackingModel
trackingModel
:
this
.
options
.
trackingModel
,
trackSubject
:
this
.
options
.
trackSubject
,
appClass
:
this
.
options
.
appClass
}
},
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment