learning mastery student view: basic info and progress bars
fixes CNVS-12922 fixes CNVS-11552 test plan: * enable learning mastery student view * open a student's grades page * open the learning mastery tab * verify that outcome groups have the correct statuses * verify that the outcome have the correct statuses * verify that the progress bars are correctly color coded and in the correct percentages Change-Id: I2aa0a73d4a831d9795308efc10cdf13123fe7dce Reviewed-on: https://gerrit.instructure.com/35844 Reviewed-by: Braden Anderson <banderson@instructure.com> Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Steven Shepherd <sshepherd@instructure.com> Product-Review: Drew Bowman <dbowman@instructure.com>
This commit is contained in:
parent
e8168f02c5
commit
66ab0c0b9b
|
@ -9,10 +9,38 @@ define [
|
|||
|
||||
count: -> @get('outcomes').length
|
||||
|
||||
mastery_count: ->
|
||||
|
||||
statusCount: (status) ->
|
||||
@get('outcomes').filter((x) ->
|
||||
x.status() == 'mastery'
|
||||
x.status() == status
|
||||
).length
|
||||
|
||||
mastery_count: ->
|
||||
@statusCount('mastery')
|
||||
|
||||
remedialCount: ->
|
||||
@statusCount('remedial')
|
||||
|
||||
undefinedCount: ->
|
||||
@statusCount('undefined')
|
||||
|
||||
status: ->
|
||||
if @remedialCount() > 0
|
||||
"remedial"
|
||||
else
|
||||
if @mastery_count() == @count()
|
||||
"mastery"
|
||||
else if @undefinedCount() == @count()
|
||||
"undefined"
|
||||
else
|
||||
"near"
|
||||
|
||||
started: ->
|
||||
true
|
||||
|
||||
toJSON: ->
|
||||
_.extend(super, count: @count(), mastery_count: @mastery_count())
|
||||
_.extend super,
|
||||
count: @count()
|
||||
mastery_count: @mastery_count()
|
||||
started: @started()
|
||||
status: @status()
|
||||
|
|
|
@ -4,14 +4,33 @@ define [
|
|||
], (_, {Model, Collection}) ->
|
||||
class Outcome extends Model
|
||||
status: ->
|
||||
score = @get('score')
|
||||
mastery = @get('mastery_points')
|
||||
if score >= mastery
|
||||
'mastery'
|
||||
else if score >= mastery / 2
|
||||
'near'
|
||||
if @scoreDefined()
|
||||
score = @get('score')
|
||||
mastery = @get('mastery_points')
|
||||
if score >= mastery
|
||||
'mastery'
|
||||
else if score >= mastery / 2
|
||||
'near'
|
||||
else
|
||||
'remedial'
|
||||
else
|
||||
'remedial'
|
||||
'undefined'
|
||||
|
||||
scoreDefined: ->
|
||||
_.isNumber(@get('score'))
|
||||
|
||||
percentProgress: ->
|
||||
if @scoreDefined()
|
||||
@get('score')/@get('points_possible') * 100
|
||||
else
|
||||
0
|
||||
|
||||
masteryPercent: ->
|
||||
@get('mastery_points')/@get('points_possible') * 100
|
||||
|
||||
toJSON: ->
|
||||
_.extend(super, status: @status())
|
||||
_.extend super,
|
||||
status: @status()
|
||||
scoreDefined: @scoreDefined()
|
||||
percentProgress: @percentProgress()
|
||||
masteryPercent: @masteryPercent()
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
define [
|
||||
'i18n!outcomes'
|
||||
'Backbone'
|
||||
'underscore'
|
||||
'compiled/views/CollectionView'
|
||||
'compiled/views/grade_summary/OutcomeView'
|
||||
'jst/grade_summary/group'
|
||||
], ({View, Collection}, _, CollectionView, OutcomeView, template) ->
|
||||
], (I18n, {View, Collection}, _, CollectionView, OutcomeView, template) ->
|
||||
|
||||
class GroupView extends View
|
||||
tagName: 'li'
|
||||
|
@ -22,3 +23,15 @@ define [
|
|||
collection: @model.get('outcomes')
|
||||
itemView: OutcomeView
|
||||
outcomesView.render()
|
||||
|
||||
statusTooltip: ->
|
||||
switch @model.status()
|
||||
when 'undefined' then I18n.t 'undefined', 'Unstarted'
|
||||
when 'remedial' then I18n.t 'remedial', 'Remedial'
|
||||
when 'near' then I18n.t 'near', 'Near mastery'
|
||||
when 'mastery' then I18n.t 'mastery', 'Mastery'
|
||||
|
||||
toJSON: ->
|
||||
json = super
|
||||
_.extend json,
|
||||
statusTooltip: @statusTooltip()
|
||||
|
|
|
@ -1,12 +1,22 @@
|
|||
define [
|
||||
'i18n!outcomes'
|
||||
'underscore'
|
||||
'Backbone'
|
||||
'jst/grade_summary/outcome'
|
||||
], (_, Backbone, template) ->
|
||||
], (I18n, _, Backbone, template) ->
|
||||
class OutcomeView extends Backbone.View
|
||||
tagName: 'li'
|
||||
className: 'outcome'
|
||||
template: template
|
||||
|
||||
statusTooltip: ->
|
||||
switch @model.status()
|
||||
when 'undefined' then I18n.t 'undefined', 'Unstarted'
|
||||
when 'remedial' then I18n.t 'remedial', 'Remedial'
|
||||
when 'near' then I18n.t 'near', 'Near mastery'
|
||||
when 'mastery' then I18n.t 'mastery', 'Mastery'
|
||||
|
||||
toJSON: ->
|
||||
json = super
|
||||
_.extend({score_defined: _.isNumber(json.score)}, json)
|
||||
_.extend json,
|
||||
statusTooltip: @statusTooltip()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// print button for grades summary page
|
||||
.print-grades
|
||||
float: right
|
||||
|
||||
|
||||
@media print
|
||||
display: none
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
|||
#grades_summary
|
||||
border-collapse: collapse
|
||||
border-bottom: 1px solid #eee
|
||||
|
||||
|
||||
@media print
|
||||
border-bottom: none
|
||||
a
|
||||
|
@ -24,7 +24,7 @@
|
|||
background-color: #444
|
||||
color: #fff
|
||||
text-align: left
|
||||
|
||||
|
||||
@media print
|
||||
:text-transform uppercase
|
||||
:color black
|
||||
|
@ -34,13 +34,13 @@
|
|||
:padding-left 0
|
||||
|
||||
#grades_summary tr
|
||||
|
||||
|
||||
> *
|
||||
padding: 5px
|
||||
text-align: left
|
||||
border-top: 2px solid black
|
||||
background-color: #fff
|
||||
|
||||
|
||||
@media print
|
||||
border-top: 1px solid black
|
||||
color: black !important
|
||||
|
@ -50,7 +50,7 @@
|
|||
border-width: 0
|
||||
font-size: 0.8em
|
||||
padding-left: 30px
|
||||
|
||||
|
||||
@media print
|
||||
padding-left: 0
|
||||
font-style: italic
|
||||
|
@ -71,7 +71,7 @@
|
|||
|
||||
#grades_summary tr.student_assignment.dropped td
|
||||
color: #ccc
|
||||
|
||||
|
||||
@media print
|
||||
color: black
|
||||
|
||||
|
@ -82,7 +82,7 @@
|
|||
|
||||
#grades_summary tr.student_assignment.dropped td a
|
||||
color: #aaa
|
||||
|
||||
|
||||
@media print
|
||||
color: black
|
||||
font-weight: normal
|
||||
|
@ -121,7 +121,7 @@
|
|||
font-weight: normal
|
||||
padding-left: 20px
|
||||
word-break: break-all
|
||||
|
||||
|
||||
@media print
|
||||
padding-left: 0
|
||||
font-size: 1.0em
|
||||
|
@ -133,7 +133,7 @@
|
|||
color: #999
|
||||
padding-left: 10px
|
||||
line-height: 0.5em
|
||||
|
||||
|
||||
@media print
|
||||
visibility: visible
|
||||
margin: 5px 0
|
||||
|
@ -145,16 +145,16 @@
|
|||
#grades_summary td.due
|
||||
font-size: 0.8em
|
||||
white-space: nowrap
|
||||
|
||||
|
||||
@media print
|
||||
font-size: 1em
|
||||
|
||||
#grades_summary tr.assignment_graded > *
|
||||
background-color: #eee
|
||||
|
||||
|
||||
@media print
|
||||
background-color: transparent
|
||||
|
||||
|
||||
&.title
|
||||
font-weight: bold
|
||||
|
||||
|
@ -163,7 +163,7 @@
|
|||
color: #eee
|
||||
font-size: 1.5em
|
||||
font-weight: bold
|
||||
|
||||
|
||||
@media print
|
||||
background-color: transparent
|
||||
text-transform: uppercase
|
||||
|
@ -175,12 +175,12 @@
|
|||
background-color: #ccc
|
||||
border-top-width: 0
|
||||
font-weight: bold
|
||||
|
||||
|
||||
@media print
|
||||
background-color: transparent
|
||||
border-top-width: 1px
|
||||
text-transform: uppercase
|
||||
|
||||
|
||||
&.title .context
|
||||
display: none
|
||||
|
||||
|
@ -312,9 +312,35 @@ $outcome-border: 1px solid #BCC2CA
|
|||
|
||||
.group-description
|
||||
overflow: hidden
|
||||
.status
|
||||
padding: 10px 50px 10px 15px
|
||||
.outcome-icon i
|
||||
line-height: 40px
|
||||
.group-title
|
||||
margin: 0
|
||||
font-size: 20px
|
||||
line-height: 40px
|
||||
.group-status
|
||||
float: right
|
||||
margin: 1em
|
||||
margin: 0
|
||||
text-align: center
|
||||
font-size: 30px
|
||||
color: #959595
|
||||
position: relative
|
||||
top: 4px
|
||||
strong
|
||||
color: #2a333b
|
||||
span
|
||||
display: block
|
||||
font-size: 14px
|
||||
|
||||
.undefined>i
|
||||
color: #C0C0C0
|
||||
.remedial>i
|
||||
color: #F76A66
|
||||
.near>i
|
||||
color: #DFB056
|
||||
.mastery>i
|
||||
color: #5DC28F
|
||||
|
||||
.outcomes
|
||||
background-color: #f7f7f7
|
||||
|
@ -326,23 +352,58 @@ $outcome-border: 1px solid #BCC2CA
|
|||
list-style-type: none
|
||||
overflow: hidden
|
||||
|
||||
.outcome-icon
|
||||
float: left
|
||||
margin-right: 15px
|
||||
|
||||
li.outcome
|
||||
padding: 20px 50px 20px 15px
|
||||
border-top: $outcome-border
|
||||
|
||||
.outcome-properties
|
||||
float: left
|
||||
width: 80%
|
||||
padding: 1em
|
||||
box-sizing: border-box
|
||||
width: 70%
|
||||
|
||||
.description
|
||||
color: #b4b4b4
|
||||
color: #2a333b
|
||||
p
|
||||
margin: 0
|
||||
|
||||
.title
|
||||
font-weight: bold
|
||||
|
||||
.score
|
||||
.outcome-score
|
||||
float: right
|
||||
width: 20%
|
||||
padding: 1em
|
||||
box-sizing: border-box
|
||||
width: 165px
|
||||
padding-top: 10px
|
||||
|
||||
.bar
|
||||
background: #e1e1e1
|
||||
height: 8px
|
||||
position: relative
|
||||
.bar-marker
|
||||
position: absolute
|
||||
width: 3px
|
||||
background: #f7f7f7
|
||||
z-index: 5
|
||||
height: 8px
|
||||
top: 0
|
||||
.bar-progress
|
||||
height: 8px
|
||||
|
||||
&.remedial
|
||||
background: #F76A66
|
||||
&.near
|
||||
background: #DFB056
|
||||
&.mastery
|
||||
background: #5DC28F
|
||||
|
||||
.score
|
||||
color: #959595
|
||||
font-size: 18px
|
||||
float: left
|
||||
strong
|
||||
color: #2a333b
|
||||
a
|
||||
float: right
|
||||
line-height: 22px
|
||||
|
|
|
@ -356,7 +356,12 @@ h1, h2, h3, h4, .h1, .h2, .h3, .h4, p {
|
|||
|
||||
|
||||
// define specific icon classes, mapped to the "canvasregular" icon font above
|
||||
|
||||
.icon-trouble:before { content: "\e600"; }
|
||||
.icon-partial:before { content: "\e601"; }
|
||||
.icon-expand:before { content: "\e602"; }
|
||||
.icon-empty:before { content: "\e603"; }
|
||||
.icon-complete:before { content: "\e604"; }
|
||||
.icon-collapse:before { content: "\e605"; }
|
||||
.icon-stats:before { content: "\e06a" }
|
||||
.icon-paperclip:before { content: "\e03d" }
|
||||
.icon-media:before { content: "\e062" }
|
||||
|
|
|
@ -1,8 +1,23 @@
|
|||
<div class="group-description">
|
||||
<h3>{{title}}</h3>
|
||||
<div class="status">
|
||||
{{mastery_count}} / {{count}}
|
||||
</div>
|
||||
<div class="outcome-icon {{status}}" data-tooltip title="{{statusTooltip}}" aria-label="Outcome Group: {{title}} status is {{statusTooltip}}">
|
||||
{{#if started}}
|
||||
{{#ifEqual status 'mastery'}}
|
||||
<i class="icon-complete"></i>
|
||||
{{else}}
|
||||
{{#ifEqual status 'near'}}
|
||||
<i class="icon-partial"></i>
|
||||
{{else}}
|
||||
<i class="icon-trouble"></i>
|
||||
{{/ifEqual}}
|
||||
{{/ifEqual}}
|
||||
{{else}}
|
||||
<i class="icon-empty"></i>
|
||||
{{/if}}
|
||||
</div>
|
||||
<h3 class="group-title">{{title}}</h3>
|
||||
<div class="group-status" aria-label="{{mastery_count}} out of {{count}} outcomes mastered">
|
||||
<strong>{{mastery_count}}</strong>/{{count}} <span>Outcomes</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="outcomes">
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,29 @@
|
|||
<div class="outcome-icon {{status}}" data-tooltip="top" title="{{statusTooltip}}" aria-label="Outcome: {{title}} has a status of {{statusTooltip}}">
|
||||
{{#if scoreDefined}}
|
||||
{{#ifEqual status 'mastery'}}
|
||||
{{addIcon 'complete'}}
|
||||
{{else}}
|
||||
{{#ifEqual status 'near'}}
|
||||
{{addIcon 'partial'}}
|
||||
{{else}}
|
||||
{{addIcon 'trouble'}}
|
||||
{{/ifEqual}}
|
||||
{{/ifEqual}}
|
||||
{{else}}
|
||||
<i class="icon-empty"></i>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="outcome-properties">
|
||||
<div class="title">{{title}}</div>
|
||||
<div class="title" data-tooltip title="{{description}}">{{title}}</div>
|
||||
<div class="description">{{{description}}}</div>
|
||||
</div>
|
||||
<div class="score">
|
||||
{{#if score_defined}}{{score}}{{else}}-{{/if}}/{{mastery_points}}
|
||||
<div class="outcome-score">
|
||||
<div class="bar">
|
||||
<div class="bar-marker" style="left: {{masteryPercent}}%"></div>
|
||||
<div class="bar-progress {{status}}" style="width: {{percentProgress}}%"></div>
|
||||
</div>
|
||||
<span class="score" aria-label="Score: {{score}} out of {{points_possible}} points with mastery at {{mastery_points}}">
|
||||
<strong>{{#if scoreDefined}}{{score}}{{else}}-{{/if}}</strong>/{{mastery_points}}
|
||||
</span>
|
||||
<a href="#"><strong>X</strong> Alignments</a>
|
||||
</div>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 109 KiB |
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,38 @@
|
|||
define [
|
||||
'compiled/models/grade_summary/Outcome'
|
||||
], (Outcome) ->
|
||||
|
||||
module "Outcome"
|
||||
|
||||
test "#status should be mastery if the score equals the mastery points", ->
|
||||
outcome = new Outcome({score: 3, mastery_points: 3})
|
||||
equal outcome.status(), 'mastery'
|
||||
|
||||
test "#status should be mastery if the score is greater than the mastery points", ->
|
||||
outcome = new Outcome({score: 4, mastery_points: 3})
|
||||
equal outcome.status(), 'mastery'
|
||||
|
||||
test "#status should be near if the score is greater than half the mastery points", ->
|
||||
outcome = new Outcome({score: 2, mastery_points: 3})
|
||||
equal outcome.status(), 'near'
|
||||
|
||||
test "#status should be remedial if the score is less than half the mastery points", ->
|
||||
outcome = new Outcome({score: 1, mastery_points: 3})
|
||||
equal outcome.status(), 'remedial'
|
||||
|
||||
test "#status should be undefined if there is no score", ->
|
||||
outcome = new Outcome({mastery_points: 3})
|
||||
equal outcome.status(), 'undefined'
|
||||
|
||||
|
||||
test "#percentProgress should be zero if score isn't defined", ->
|
||||
outcome = new Outcome({points_possible: 3})
|
||||
equal outcome.percentProgress(), 0
|
||||
|
||||
test "#percentProgress should be score over points possible", ->
|
||||
outcome = new Outcome({score: 5, points_possible: 10})
|
||||
equal outcome.percentProgress(), 50
|
||||
|
||||
test "#masteryPercent should be master_points over points possible", ->
|
||||
outcome = new Outcome({mastery_points: 5, points_possible: 10})
|
||||
equal outcome.masteryPercent(), 50
|
Loading…
Reference in New Issue