show points per role in milestone

stable
Juanfran 2016-07-05 12:08:11 +02:00 committed by David Barragán Merino
parent 065a3af3d6
commit 528457dbca
6 changed files with 133 additions and 25 deletions

View File

@ -12,6 +12,7 @@
- Display the current user (me) at first in assignment lightbox (thanks to [@mikaoelitiana](https://github.com/mikaoelitiana)) - Display the current user (me) at first in assignment lightbox (thanks to [@mikaoelitiana](https://github.com/mikaoelitiana))
- Divide the user dashboard in two columns in large screens, - Divide the user dashboard in two columns in large screens,
- Upvote and downvote issues from the issues list. - Upvote and downvote issues from the issues list.
- Show points per role in statsection of the taskboard panel.
- Comments: - Comments:
- Add a new permissions to allow add comments instead of use the existent modify permission for this purpose. - Add a new permissions to allow add comments instead of use the existent modify permission for this purpose.
- Ability to edit comments, view edition history and redesign comments module UI. - Ability to edit comments, view edition history and redesign comments module UI.

View File

@ -220,6 +220,7 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin)
return promise.then(=> @.loadProject()) return promise.then(=> @.loadProject())
.then(=> @.loadTaskboard()) .then(=> @.loadTaskboard())
.then(=> @.setRolePoints())
refreshTasksOrder: (tasks) -> refreshTasksOrder: (tasks) ->
items = @.resortTasks(tasks) items = @.resortTasks(tasks)
@ -273,6 +274,33 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin)
editTaskAssignedTo: (task) -> editTaskAssignedTo: (task) ->
@rootscope.$broadcast("assigned-to:add", task) @rootscope.$broadcast("assigned-to:add", task)
setRolePoints: () ->
computableRoles = _.filter(@scope.project.roles, "computable")
getRole = (roleId) =>
roleId = parseInt(roleId, 10)
return _.find computableRoles, (role) -> role.id == roleId
getPoint = (pointId) =>
poitnId = parseInt(pointId, 10)
return _.find @scope.project.points, (point) -> point.id == pointId
pointsByRole = _.reduce @scope.userstories, (result, us, key) =>
_.forOwn us.points, (pointId, roleId) ->
role = getRole(roleId)
point = getPoint(pointId)
if !result[role.id]
result[role.id] = role
result[role.id].points = 0
result[role.id].points += point.value
return result
, {}
@scope.pointsByRole = Object.keys(pointsByRole).map (key) -> return pointsByRole[key]
module.controller("TaskboardController", TaskboardController) module.controller("TaskboardController", TaskboardController)

View File

@ -1151,7 +1151,8 @@
"CLOSED_TASKS": "closed<br />tasks", "CLOSED_TASKS": "closed<br />tasks",
"IOCAINE_DOSES": "iocaine<br />doses", "IOCAINE_DOSES": "iocaine<br />doses",
"SHOW_STATISTICS_TITLE": "Show statistics", "SHOW_STATISTICS_TITLE": "Show statistics",
"TOGGLE_BAKLOG_GRAPH": "Show/Hide burndown graph" "TOGGLE_BAKLOG_GRAPH": "Show/Hide burndown graph",
"POINTS_PER_ROLE": "Points per role"
}, },
"SUMMARY": { "SUMMARY": {
"PROJECT_POINTS": "project<br />points", "PROJECT_POINTS": "project<br />points",

View File

@ -1,29 +1,44 @@
div.summary.large-summary div.summary.large-summary
div.large-summary-wrapper div.large-summary-wrapper
div.summary-progress-wrapper .summary-progress-wrapper
div.summary-progress-bar(tg-progress-bar="stats.completedPercentage") div.summary-progress-bar(tg-progress-bar="stats.completedPercentage")
div.data div.data
span.number(ng-bind="stats.completedPercentage + '%'") span.number(ng-bind="stats.completedPercentage + '%'")
div.summary-stats .stats-wrapper(ng-class="{'show-role-points': showRolePoints}")
span.number(ng-bind="stats.totalPointsSum|default:'--'") .main-summary-stats
span.description(translate="BACKLOG.SPRINT_SUMMARY.TOTAL_POINTS") span.summary-stats.toggle-points-per-role(ng-click="showRolePoints = true")
div.summary-stats tg-svg(svg-icon="icon-arrow-down")
span.number(ng-bind="stats.completedPointsSum|default:'--'") span.number(ng-bind="stats.totalPointsSum|default:'--'")
span.description(translate="BACKLOG.SPRINT_SUMMARY.COMPLETED_POINTS") span.description(translate="BACKLOG.SPRINT_SUMMARY.TOTAL_POINTS")
div.summary-stats.summary-completed-points
span.number(ng-bind="stats.completedPointsSum|default:'--'")
span.description(translate="BACKLOG.SPRINT_SUMMARY.COMPLETED_POINTS")
div.summary-stats div.summary-stats.summary-open-tasks
tg-svg(svg-icon="icon-bulk") tg-svg(svg-icon="icon-bulk")
span.number(ng-bind="stats.openTasks|default:'--'") span.number(ng-bind="stats.openTasks|default:'--'")
span.description(translate="BACKLOG.SPRINT_SUMMARY.OPEN_TASKS") span.description(translate="BACKLOG.SPRINT_SUMMARY.OPEN_TASKS")
div.summary-stats div.summary-stats.summary-closed-tasks
span.number(ng-bind="stats.completed_tasks|default:'--'") span.number(ng-bind="stats.completed_tasks|default:'--'")
span.description(translate="BACKLOG.SPRINT_SUMMARY.CLOSED_TASKS") span.description(translate="BACKLOG.SPRINT_SUMMARY.CLOSED_TASKS")
div.summary-stats(title="{{'COMMON.IOCAINE_TEXT' | translate}}") div.summary-stats.summary-iocaine(title="{{'COMMON.IOCAINE_TEXT' | translate}}")
tg-svg(svg-icon="icon-iocaine") tg-svg(svg-icon="icon-iocaine")
span.number(ng-bind="stats.iocaine_doses|default:'--'") span.number(ng-bind="stats.iocaine_doses|default:'--'")
span.description(translate="BACKLOG.SPRINT_SUMMARY.IOCAINE_DOSES") span.description(translate="BACKLOG.SPRINT_SUMMARY.IOCAINE_DOSES")
.points-per-role-stats.toggle-points-per-role(
ng-click="showRolePoints = false"
)
span.points-per-role-stats-title
tg-svg(svg-icon="icon-arrow-up")
span(translate="BACKLOG.SPRINT_SUMMARY.POINTS_PER_ROLE")
.points-per-role-stats-content
.summary-stats(ng-repeat="rolePoint in pointsByRole")
span.number {{rolePoint.points}}
span.role {{rolePoint.name}}
div.stats.toggle-analytics-visibility(title="{{'BACKLOG.SPRINT_SUMMARY.SHOW_STATISTICS_TITLE' | translate}}") div.stats.toggle-analytics-visibility(title="{{'BACKLOG.SPRINT_SUMMARY.SHOW_STATISTICS_TITLE' | translate}}")
tg-svg(svg-icon="icon-graph") tg-svg(svg-icon="icon-graph")

View File

@ -1,6 +1,7 @@
header(tg-backlog-sprint-header, ng-model="sprint") header(tg-backlog-sprint-header, ng-model="sprint")
div.sprint-progress-bar(tg-progress-bar="100 * sprint.closed_points / sprint.total_points") .summary-progress-wrapper
div.sprint-progress-bar(tg-progress-bar="100 * sprint.closed_points / sprint.total_points")
div.sprint-table(tg-bind-scope, ng-class="{'sprint-empty-wrapper': !sprint.user_stories.length}") div.sprint-table(tg-bind-scope, ng-class="{'sprint-empty-wrapper': !sprint.user_stories.length}")
div.sprint-empty(ng-if="!sprint.user_stories.length") div.sprint-empty(ng-if="!sprint.user_stories.length")

View File

@ -2,14 +2,18 @@ $summary-background: $grayer;
.summary { .summary {
align-content: center; align-content: center;
align-items: center;
background: $summary-background; background: $summary-background;
color: $white; color: $white;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
height: 65px;
justify-content: flex-start; justify-content: flex-start;
margin-bottom: 2rem; margin-bottom: 2rem;
padding: 1em; overflow: hidden;
padding: 1rem;
.summary-stats { .summary-stats {
align-items: center;
display: flex; display: flex;
margin: 0 .5rem; margin: 0 .5rem;
} }
@ -20,7 +24,7 @@ $summary-background: $grayer;
} }
.number { .number {
@include font-size(xlarge); @include font-size(xlarge);
@include font-type(bold); @include font-type(light);
line-height: .9; line-height: .9;
margin-right: .3rem; margin-right: .3rem;
} }
@ -69,6 +73,21 @@ $summary-background: $grayer;
transition: fill .2s; transition: fill .2s;
} }
} }
.main-summary-stats {
display: flex;
transform: translateY(0);
transition: all .2s ease-in-out;
}
.show-role-points {
.points-per-role-stats {
transform: translateY(-35px);
}
.main-summary-stats {
transform: translateY(-65px);
}
}
} }
.summary-progress-bar { .summary-progress-bar {
@ -102,7 +121,12 @@ $summary-background: $grayer;
} }
.large-summary { .large-summary {
align-items: stretch;
justify-content: space-between; justify-content: space-between;
padding: .75rem 1rem;
.stats-wrapper {
padding-top: .35rem;
}
.large-summary-wrapper { .large-summary-wrapper {
align-content: center; align-content: center;
display: flex; display: flex;
@ -110,6 +134,7 @@ $summary-background: $grayer;
justify-content: flex-start; justify-content: flex-start;
} }
.summary-progress-wrapper { .summary-progress-wrapper {
align-items: center;
display: flex; display: flex;
} }
.summary-progress-bar { .summary-progress-bar {
@ -122,13 +147,23 @@ $summary-background: $grayer;
border: 0; border: 0;
margin: 0; margin: 0;
} }
&.summary-completed-points,
&.summary-closed-tasks {
border-right: 1px solid $blackish;
margin-right: 0;
padding-right: 1rem;
+.summary-stats {
border-left: 1px solid $gray;
margin-left: 0;
padding-left: 1rem;
}
}
} }
.icon { .icon {
@include svg-size(1.3rem);
fill: currentColor; fill: currentColor;
height: 1.5rem;
margin-right: .4rem; margin-right: .4rem;
vertical-align: middle; vertical-align: middle;
width: 1.5rem;
&.icon-stats { &.icon-stats {
color: $primary; color: $primary;
float: right; float: right;
@ -146,6 +181,33 @@ $summary-background: $grayer;
} }
} }
} }
.points-per-role-stats-content {
display: flex;
padding-left: 1rem;
.summary-stats {
padding: 0;
}
}
.toggle-points-per-role {
color: $white;
cursor: pointer;
svg {
@include svg-size();
}
}
.points-per-role-stats {
margin-left: .5rem;
transform: translateY(35px);
transition: all .2s ease-in-out;
.number {
@include font-size(large);
@include font-type(normal);
}
.role {
@include font-size(xsmall);
@include font-type(light);
}
}
} }
.empty-burndown { .empty-burndown {