Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 25ad101

Browse files
committedJun 11, 2013
add tekken bar
1 parent 9a3df95 commit 25ad101

File tree

5 files changed

+270
-7
lines changed

5 files changed

+270
-7
lines changed
 

‎por/dashboard/forms/project.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -248,16 +248,16 @@ def customer_requests(self, *args, **kwargs):
248248
params = Backlog(self.request).backlog(projects=[project])
249249
params['request'] = self.request
250250
params['context'] = self.request.context
251+
params['all_contracts'] = project.contracts
251252
params['multiple_bgb'] = False
252-
253253
# override backlog permissions.
254254
# if the user is not a developer/pm/admin, deny the view of placement and done time entries
255255
roles = self.request.authenticated_user.roles_in_context(project)
256256

257257
if not roles.intersection(set(['administrator', 'project_manager', 'internal_developer','secretary'])):
258258
params['can_view_placement'] = False
259259

260-
return SkinObject('backlog')(**params)
260+
return SkinObject('tekken')(**params)
261261

262262

263263
@actions.action('documentation')

‎por/dashboard/skins/tekken.pt

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<!DOCTYPE html>
2+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
3+
xmlns:tal="http://xml.zope.org/namespaces/tal"
4+
metal:use-macro="skin: /main_template">
5+
6+
<head metal:fill-slot="javascript">
7+
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
8+
<script type="text/javascript">
9+
google.load('visualization', '1', {packages: ['corechart']});
10+
</script>
11+
<script type="text/javascript" src="${request.application_url}/static/por_backlog/tekken.js"></script>
12+
</head>
13+
<body>
14+
15+
<div metal:fill-slot="body" tal-omit-tag="">
16+
17+
<div id="visualization" style="width: 600px; height: 100px;"></div>
18+
19+
<form id="tekken-filter">
20+
<div class="subnav">
21+
<select id="contract" name="contract">
22+
<option tal:repeat="contract all_contracts" value="${contract.id}">${contract.name}</option>
23+
</select>
24+
</div>
25+
<div class="subnav">
26+
<ul class="nav">
27+
<li class="pull-left">
28+
</li>
29+
<li tal:condition="can_view_placement"
30+
tal:repeat="placement cr_placements" class="pull-left">
31+
<input type="checkbox"
32+
id="placement_${placement[0]}"
33+
name="placement_${placement[0]}"
34+
value="${placement[0]}"
35+
checked="${'checked' if placement[0] in cr_placements_active else nothing}" />
36+
<label for="placement_${placement[0]}" class="label label-${placement[2]}">
37+
${placement[1]}
38+
</label>
39+
</li>
40+
<li tal:repeat="wf_state cr_workflow_states" class="pull-left">
41+
<input type="checkbox"
42+
id="workflow_${wf_state[0]}"
43+
name="workflow_${wf_state[0]}"
44+
value="${wf_state[0]}"
45+
checked="${'checked' if wf_state[0] in cr_workflow_active else nothing}" />
46+
<label for="workflow_${wf_state[0]}">
47+
${wf_state[1]}
48+
</label>
49+
</li>
50+
</ul>
51+
</div>
52+
</form>
53+
54+
<metal:body define-macro="report-main">
55+
<table class="bgb-container table-condensed">
56+
<colgroup>
57+
<col tal:condition="can_view_placement" class="col-placement" />
58+
<col class="col-customer-request" />
59+
<col class="col-workflow-state" />
60+
<col tal:condition="can_view_estimate_column" class="col-estimated" />
61+
<col tal:condition="can_view_done_column" class="col-done" />
62+
<col tal:condition="can_view_percentage_column" class="col-done" />
63+
</colgroup>
64+
<thead>
65+
<tr class="backlog-table-headers">
66+
<th tal:condition="can_view_placement">&nbsp;</th>
67+
<th>&nbsp;</th>
68+
<th class="backlog-workflow">state</th>
69+
<th tal:condition="can_view_estimate_column" class="backlog-duration">estimated</th>
70+
<th tal:condition="can_view_done_column" class="backlog-duration">done</th>
71+
<th tal:condition="can_view_percentage_column" class="backlog-duration">percentage</th>
72+
</tr>
73+
</thead>
74+
<tal:bgb repeat="bgb bgbs">
75+
<tbody class="bgb-project-header">
76+
<tr>
77+
<td colspan="${3 if can_view_placement else 2}">
78+
${bgb.project.customer.name} / ${bgb.project.name}
79+
</td>
80+
<td tal:condition="can_view_estimate_column" class="backlog-duration"><span class="total-estimate"></span></td>
81+
<td tal:condition="can_view_done_column" class="backlog-duration"><span class="total-done"></span></td>
82+
<td tal:condition="can_view_percentage_column" class="backlog-duration"><span class="total-percentage"></span></td>
83+
</tr>
84+
</tbody>
85+
<tbody class="bgb-project table">
86+
<tal:cr repeat="cr sorted(bgb.project.customer_requests, key=unicodelower)">
87+
<tr data-cr-id="${cr.id}"
88+
data-placement="${cr.placement if can_view_placement else nothing}"
89+
data-cr-editable="${1 if can_edit_cr[cr] else nothing}"
90+
data-workflow-state="${cr.workflow_state}"
91+
data-contract="${cr.contract and cr.contract.id or ''}"
92+
data-contract-days="${cr.contract and cr.contract.days or ''}"
93+
data-duration-estimate="${bgb.get_estimate(cr) if can_view_estimate[bgb.project] else nothing}"
94+
data-duration-percentage="${bgb.get_percentage(cr) if can_view_percentage[bgb.project] else nothing}"
95+
data-duration-done="${bgb.get_done(cr) if can_view_done[bgb.project] else nothing}">
96+
<td tal:condition="can_view_placement">&nbsp;</td>
97+
<td>
98+
<a href="/admin/CustomerRequest/${cr.id}">
99+
${cr.name}
100+
</a>
101+
</td>
102+
<td class="backlog-workflow">${cr.workflow_state}</td>
103+
<td tal:condition="can_view_estimate_column" class="backlog-duration">&nbsp;</td>
104+
<td tal:condition="can_view_done_column" class="backlog-duration">&nbsp;</td>
105+
<td tal:condition="can_view_percentage_column" class="backlog-duration">&nbsp;</td>
106+
</tr>
107+
</tal:cr>
108+
<tr>
109+
<td tal:condition="can_view_placement">&nbsp;</td>
110+
<td>&nbsp;</td>
111+
<td>&nbsp;</td>
112+
<td tal:condition="can_view_estimate_column">&nbsp;</td>
113+
<td tal:condition="can_view_done_column">&nbsp;</td>
114+
<td tal:condition="can_view_percentage_column">&nbsp;</td>
115+
</tr>
116+
</tbody>
117+
</tal:bgb>
118+
<tfoot class="backlog-no-rows hide">
119+
<td tal:condition="can_view_placement">&nbsp;</td>
120+
<td colspan="2">No customer request matches the selection.</td>
121+
<td tal:condition="can_view_estimate_column">&nbsp;</td>
122+
<td tal:condition="can_view_done_column">&nbsp;</td>
123+
<td tal:condition="can_view_percentage_column">&nbsp;</td>
124+
</tfoot>
125+
</table>
126+
127+
</metal:body>
128+
129+
</div>
130+
131+
</body>
132+
</html>

‎por/dashboard/static/por_backlog/backlog.css

+21
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,24 @@ tr[data-cr-editable] .backlog-placement-trigger {
8484
background-color: transparent;
8585
}
8686

87+
#tekken-filter ul {
88+
padding-top: 5px;
89+
}
90+
91+
#tekken-filter .subnav.subnav-fixed ul {
92+
padding-left: 50px;
93+
}
94+
95+
#tekken-filter li {
96+
float: left;
97+
padding-left: 8px;
98+
}
99+
100+
#tekken-filter li > input {
101+
float: left;
102+
margin-right: 3px;
103+
}
104+
105+
#tekken-filter li > label {
106+
float: left;
107+
}

‎por/dashboard/static/por_backlog/backlog.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,12 @@ $(document).ready(function(){
116116
// checks if a given row is selected from the main filter
117117
var check_filter = function($tr) {
118118
var $chk_placement = $('#placement_'+$tr.data('placement')),
119-
$chk_workflow = $('#workflow_'+$tr.data('workflow-state'));
120-
119+
$chk_workflow = $('#workflow_'+$tr.data('workflow-state')),
120+
$chk_contract = $('#contract').val() === $tr.data('contract');
121121
return (
122122
(($chk_placement.length===0) || $chk_placement.is(':checked')) &&
123-
(($chk_workflow.length===0) || $chk_workflow.is(':checked'))
123+
(($chk_workflow.length===0) || $chk_workflow.is(':checked')) &&
124+
($chk_contract)
124125
);
125126
};
126127

@@ -196,8 +197,6 @@ $(document).ready(function(){
196197
fill_percentage($('.bigtotal-percentage'), bigtotal_percentage);
197198
};
198199

199-
200-
201200
// upon clicking the header, show/collapse the project's bgb
202201
// the header will not be clickable (no trigger class) if there is only one project in the page
203202
$('.bgb-project-trigger').click(function(ev) {
@@ -251,6 +250,8 @@ $(document).ready(function(){
251250
};
252251

253252
$('#backlog-filter input').change(refresh_trs);
253+
$('#tekken-filter input').change(refresh_trs);
254+
$('#tekken-filter select').change(refresh_trs);
254255
refresh_trs();
255256

256257

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
var tekken;
2+
var tekkendata;
3+
var showfiller = true;
4+
5+
function drawChart(){
6+
function TimeEntriesEnd(data, rowNum){
7+
return data.getValue(rowNum, 0)
8+
}
9+
function CR2Perc(data, rowNum){
10+
return Math.floor(data.getValue(rowNum, 1) / data.getValue(rowNum, 2) * 100)
11+
}
12+
function Filler2Perc(data, rowNum){
13+
return Math.floor((data.getValue(rowNum, 2) - data.getValue(rowNum, 1)) / data.getValue(rowNum, 2) * 100)
14+
}
15+
function CRTooltip(data, rowNum){
16+
return '<p id="first_tooltip" class="google-visualization-tooltip-item"><strong>Estimated CR:</strong> ' + data.getValue(rowNum,1) + ' days<br/><strong>Total project:</strong> ' + data.getValue(rowNum, 2) + ' days<br/><strong>Time entries:</strong> ' + data.getValue(rowNum, 0) + ' days</p>'
17+
}
18+
var view=new google.visualization.DataView(tekkendata);
19+
columns = [{calc: function() {return ''}, type: 'string'},
20+
{calc: CR2Perc, type: 'number'},
21+
{calc: function() {return 0}, type: 'number', role:'interval'},
22+
{calc: TimeEntriesEnd, type: 'number', role:'interval'},
23+
{calc: CRTooltip, type: 'string', role:'tooltip', 'properties': {'html':true}},
24+
]
25+
if (showfiller){
26+
columns.push({calc: Filler2Perc, type: 'number'})
27+
columns.push({calc: function() {return 'Filler CR'}, type: 'string', role:'tooltip'})
28+
}
29+
view.setColumns(columns);
30+
tekken.draw(view,
31+
{title:"Tekken bar",
32+
width:800, height:90,
33+
legend: 'none',
34+
isStacked: true,
35+
colors: ['#468847', '#F89406'],
36+
animation:{
37+
duration: 1000,
38+
easing: 'out',
39+
},
40+
chartArea: {left:'0'},
41+
tooltip: {isHtml: true },
42+
hAxis: {viewWindowMode:'explicit',
43+
viewWindow:{
44+
max:100.1,
45+
min:0
46+
}
47+
}
48+
}
49+
);
50+
}
51+
52+
function drawVisualization() {
53+
// Create and populate the data table.
54+
tekkendata = new google.visualization.DataTable();
55+
tekkendata.addColumn('number', 'Time Entries');
56+
tekkendata.addColumn('number', 'CR estimated');
57+
tekkendata.addColumn('number', 'Total project');
58+
tekkendata.addRows(1);
59+
tekken = new google.visualization.BarChart(document.getElementById('visualization'));
60+
google.visualization.events.addListener(tekken, 'onmouseover', refresh_te);
61+
google.visualization.events.addListener(tekken, 'onmouseout', refresh_te);
62+
google.visualization.events.addListener(tekken, 'select', refresh_te);
63+
google.visualization.events.addListener(tekken, 'ready', refresh_te);
64+
google.visualization.events.addListener(tekken, 'animationfinish', refresh_te);
65+
66+
function refresh_te(){
67+
$('path').attr('stroke', 'white').attr('stroke-width','2');
68+
$('#first_tooltip').parent().css('left', '-=220');
69+
};
70+
drawChart()
71+
}
72+
73+
google.setOnLoadCallback(function() {
74+
drawVisualization();
75+
76+
// update the total duration for a single table
77+
var update_project_totals = function($bgb_header) {
78+
var totals = {},
79+
total_estimate = 0,
80+
total_done = 0,
81+
total_days = 0,
82+
$bgb = $bgb_header.next('.bgb-project');
83+
84+
$bgb.find('tr[data-workflow-state]:visible').each(function() {
85+
total_estimate += parseInt($(this).data('duration-estimate'), 10);
86+
total_done += parseInt($(this).data('duration-done'), 10);
87+
total_days = parseInt($(this).data('contract-days'), 10);
88+
});
89+
return {
90+
total_estimate: Math.round(total_estimate / 60 / 60 / 8),
91+
total_done: Math.round(total_done / 60/ 60 / 8),
92+
total_days: total_days,
93+
};
94+
};
95+
96+
// update the tekken bar
97+
var update_tekken = function() {
98+
var totals = update_project_totals($('.bgb-project-header'));
99+
tekkendata.setValue(0, 0, totals.total_done);
100+
tekkendata.setValue(0, 1, totals.total_estimate);
101+
tekkendata.setValue(0, 2, totals.total_days);
102+
drawChart();
103+
};
104+
105+
$('#tekken-filter input').change(update_tekken);
106+
$('#tekken-filter select').change(update_tekken);
107+
update_tekken();
108+
109+
});

0 commit comments

Comments
 (0)
Please sign in to comment.