diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0c840d86..64e9cc8f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@
- 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,
- Upvote and downvote issues from the issues list.
+- Show points per role in statsection of the taskboard panel.
- Comments:
- 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.
diff --git a/app/coffee/modules/taskboard/main.coffee b/app/coffee/modules/taskboard/main.coffee
index 68620f62..d52d8dff 100644
--- a/app/coffee/modules/taskboard/main.coffee
+++ b/app/coffee/modules/taskboard/main.coffee
@@ -220,6 +220,7 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin)
return promise.then(=> @.loadProject())
.then(=> @.loadTaskboard())
+ .then(=> @.setRolePoints())
refreshTasksOrder: (tasks) ->
items = @.resortTasks(tasks)
@@ -273,6 +274,33 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin)
editTaskAssignedTo: (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)
diff --git a/app/locales/taiga/locale-en.json b/app/locales/taiga/locale-en.json
index 83b897de..16777909 100644
--- a/app/locales/taiga/locale-en.json
+++ b/app/locales/taiga/locale-en.json
@@ -1151,7 +1151,8 @@
"CLOSED_TASKS": "closed
tasks",
"IOCAINE_DOSES": "iocaine
doses",
"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": {
"PROJECT_POINTS": "project
points",
diff --git a/app/partials/includes/components/sprint-summary.jade b/app/partials/includes/components/sprint-summary.jade
index 364a336a..b4f5f6ac 100644
--- a/app/partials/includes/components/sprint-summary.jade
+++ b/app/partials/includes/components/sprint-summary.jade
@@ -1,29 +1,44 @@
div.summary.large-summary
div.large-summary-wrapper
- div.summary-progress-wrapper
+ .summary-progress-wrapper
div.summary-progress-bar(tg-progress-bar="stats.completedPercentage")
div.data
- span.number(ng-bind="stats.completedPercentage + '%'")
+ span.number(ng-bind="stats.completedPercentage + '%'")
- div.summary-stats
- span.number(ng-bind="stats.totalPointsSum|default:'--'")
- span.description(translate="BACKLOG.SPRINT_SUMMARY.TOTAL_POINTS")
- div.summary-stats
- span.number(ng-bind="stats.completedPointsSum|default:'--'")
- span.description(translate="BACKLOG.SPRINT_SUMMARY.COMPLETED_POINTS")
+ .stats-wrapper(ng-class="{'show-role-points': showRolePoints}")
+ .main-summary-stats
+ span.summary-stats.toggle-points-per-role(ng-click="showRolePoints = true")
+ tg-svg(svg-icon="icon-arrow-down")
+ span.number(ng-bind="stats.totalPointsSum|default:'--'")
+ 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
- tg-svg(svg-icon="icon-bulk")
- span.number(ng-bind="stats.openTasks|default:'--'")
- span.description(translate="BACKLOG.SPRINT_SUMMARY.OPEN_TASKS")
- div.summary-stats
- span.number(ng-bind="stats.completed_tasks|default:'--'")
- span.description(translate="BACKLOG.SPRINT_SUMMARY.CLOSED_TASKS")
+ div.summary-stats.summary-open-tasks
+ tg-svg(svg-icon="icon-bulk")
+ span.number(ng-bind="stats.openTasks|default:'--'")
+ span.description(translate="BACKLOG.SPRINT_SUMMARY.OPEN_TASKS")
+ div.summary-stats.summary-closed-tasks
+ span.number(ng-bind="stats.completed_tasks|default:'--'")
+ span.description(translate="BACKLOG.SPRINT_SUMMARY.CLOSED_TASKS")
- div.summary-stats(title="{{'COMMON.IOCAINE_TEXT' | translate}}")
- tg-svg(svg-icon="icon-iocaine")
- span.number(ng-bind="stats.iocaine_doses|default:'--'")
- span.description(translate="BACKLOG.SPRINT_SUMMARY.IOCAINE_DOSES")
+ div.summary-stats.summary-iocaine(title="{{'COMMON.IOCAINE_TEXT' | translate}}")
+ tg-svg(svg-icon="icon-iocaine")
+ span.number(ng-bind="stats.iocaine_doses|default:'--'")
+ 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}}")
tg-svg(svg-icon="icon-graph")
diff --git a/app/partials/includes/modules/sprint.jade b/app/partials/includes/modules/sprint.jade
index f56ca58b..d66c5ca7 100644
--- a/app/partials/includes/modules/sprint.jade
+++ b/app/partials/includes/modules/sprint.jade
@@ -1,6 +1,7 @@
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-empty(ng-if="!sprint.user_stories.length")
diff --git a/app/styles/components/summary.scss b/app/styles/components/summary.scss
index 2b9a8cda..52e419fd 100644
--- a/app/styles/components/summary.scss
+++ b/app/styles/components/summary.scss
@@ -2,14 +2,18 @@ $summary-background: $grayer;
.summary {
align-content: center;
+ align-items: center;
background: $summary-background;
color: $white;
display: flex;
flex-wrap: wrap;
+ height: 65px;
justify-content: flex-start;
margin-bottom: 2rem;
- padding: 1em;
+ overflow: hidden;
+ padding: 1rem;
.summary-stats {
+ align-items: center;
display: flex;
margin: 0 .5rem;
}
@@ -20,7 +24,7 @@ $summary-background: $grayer;
}
.number {
@include font-size(xlarge);
- @include font-type(bold);
+ @include font-type(light);
line-height: .9;
margin-right: .3rem;
}
@@ -69,6 +73,21 @@ $summary-background: $grayer;
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 {
@@ -102,7 +121,12 @@ $summary-background: $grayer;
}
.large-summary {
+ align-items: stretch;
justify-content: space-between;
+ padding: .75rem 1rem;
+ .stats-wrapper {
+ padding-top: .35rem;
+ }
.large-summary-wrapper {
align-content: center;
display: flex;
@@ -110,6 +134,7 @@ $summary-background: $grayer;
justify-content: flex-start;
}
.summary-progress-wrapper {
+ align-items: center;
display: flex;
}
.summary-progress-bar {
@@ -122,13 +147,23 @@ $summary-background: $grayer;
border: 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 {
+ @include svg-size(1.3rem);
fill: currentColor;
- height: 1.5rem;
margin-right: .4rem;
vertical-align: middle;
- width: 1.5rem;
&.icon-stats {
color: $primary;
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 {