Merge lp:~james-w/launchpad-work-items-tracker/workitem-list-pages into lp:~linaro-automation/launchpad-work-items-tracker/linaro

Proposed by James Westby
Status: Merged
Merged at revision: 276
Proposed branch: lp:~james-w/launchpad-work-items-tracker/workitem-list-pages
Merge into: lp:~linaro-automation/launchpad-work-items-tracker/linaro
Diff against target: 232 lines (+113/-25)
6 files modified
generate-all (+5/-0)
html-report (+42/-0)
report_tools.py (+19/-0)
templates/base.html (+12/-5)
templates/overview.html (+6/-20)
templates/workitem_list.html (+29/-0)
To merge this branch: bzr merge lp:~james-w/launchpad-work-items-tracker/workitem-list-pages
Reviewer Review Type Date Requested Status
Guilherme Salgado (community) Approve
Review via email: mp+51393@code.launchpad.net

Description of the change

Hi,

Here's a branch that goes part way to addressing bug 720346.

I haven't yet worked out how to do the per-team lists nicely, so let's start
with everything in one table.

Thanks,

James

To post a comment you must log in.
Revision history for this message
Guilherme Salgado (salgado) wrote :
Download full text (8.5 KiB)

Hi James,

I think this looks good but the new functions/methods would benefit from
some docstrings. I also have a few comments below.

 review approve

On Sat, 2011-02-26 at 01:02 +0000, James Westby wrote:
[...]
> === modified file 'generate-all'
> --- generate-all 2011-02-06 20:00:12 +0000
> +++ generate-all 2011-02-26 01:01:57 +0000
> @@ -133,6 +133,11 @@
> basename = os.path.join(opts.output_dir, "about")
> report_tools.about_page(my_path, opts.database, basename, opts.config, root=opts.root)
>
> +# workitems in status pages
> +for status in report_tools.valid_states:
> + basename = os.path.join(opts.output_dir, status)
> + report_tools.workitem_list(my_path, opts.database, basename, opts.config, status, root=opts.root)
> +
> # front page
> basename = os.path.join(opts.output_dir, 'index')
> report_tools.status_overview(my_path, opts.database, basename, opts.config, root=opts.root)
>
> === modified file 'html-report'
> --- html-report 2011-02-25 02:56:48 +0000
> +++ html-report 2011-02-26 01:01:57 +0000
> @@ -47,6 +47,7 @@
> self.priority = priority
> self.status = status
>
> +
> class Assignee(WorkitemTarget):
>
> def __init__(self, name, url, complexity=0, todo_wis=[],
> @@ -90,6 +91,19 @@
> return any([g.priority for g in self.groups])
>
>
> +class Workitem(object):
> +
> + def __init__(self, description, status, blueprint, assignee=None):
> + self.description = description
> + self.status = status
> + self.blueprint = blueprint
> + self._assignee = assignee
> +
> + @property
> + def assignee(self):
> + return self._assignee or self.blueprint.assignee
> +
> +
> def spec_group_completion(db, team, milestone):
> data = report_tools.spec_group_completion(db, team, milestone)
> if not data:
> @@ -286,6 +300,21 @@
> return group
>
>
> +def workitems_in_status(db, status, team=None, milestone=None):
> + data = report_tools.assignee_completion(
> + db, team=team, milestone=milestone)
> + workitems = []
> + for assignee in data:
> + if status in data[assignee]:
> + for wi_info in data[assignee][status]:
> + bp_name, description, priority, url = wi_info
> + blueprint = Blueprint(bp_name, url, priority=priority)
> + workitems.append(
> + Workitem(description, status, blueprint,
> + assignee=assignee))
> + return workitems
> +
> +
> def list_people(db, team=None):
> team_info = report_tools.team_information(db, team=team)
> if team is None:
> @@ -398,6 +427,17 @@
> data.update(dict(page_type="about"))
> print report_tools.fill_template("about.html", data)
>
> + def workitem_list(self, db, opts):
> + assert opts.status is not None, (
> + "Must pass --status for workitem_list report-type")
> + workitems = workitems_in_status(
> + db, opts.status, team=opts.team, milestone=opts.milestone)
> + data = self.template_data(db, opts)
> + data.update(dict(status=opts.status))
> + data.update(dict(workitems=workitems))
> + ...

Read more...

review: Approve
Revision history for this message
James Westby (james-w) wrote :

> Hi James,
>
> I think this looks good but the new functions/methods would benefit from
> some docstrings.

I will add some, thanks.

> Why 3 update() calls instead of just one passing a dict combining
> everything?

No reason really, I'll change it.

> > + $(".workitems_in_status").tablesorter({
> > + sortList: [[1,1],[0,0],[2,0]],
>
> Maybe a comment explaining these magic numbers?

Good idea.

> To make this even nicer you could add something like a
> valid_states_with_labels to report_tools (by zip()ping a list containing
> the lables with the existing valid_states there). :)

I'll do that. I need to see if we can import directly, because
passing it in the data dict would be a bit of a hassle.

Thanks,

James

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'generate-all'
2--- generate-all 2011-02-06 20:00:12 +0000
3+++ generate-all 2011-02-26 01:02:30 +0000
4@@ -133,6 +133,11 @@
5 basename = os.path.join(opts.output_dir, "about")
6 report_tools.about_page(my_path, opts.database, basename, opts.config, root=opts.root)
7
8+# workitems in status pages
9+for status in report_tools.valid_states:
10+ basename = os.path.join(opts.output_dir, status)
11+ report_tools.workitem_list(my_path, opts.database, basename, opts.config, status, root=opts.root)
12+
13 # front page
14 basename = os.path.join(opts.output_dir, 'index')
15 report_tools.status_overview(my_path, opts.database, basename, opts.config, root=opts.root)
16
17=== modified file 'html-report'
18--- html-report 2011-02-25 02:56:48 +0000
19+++ html-report 2011-02-26 01:02:30 +0000
20@@ -47,6 +47,7 @@
21 self.priority = priority
22 self.status = status
23
24+
25 class Assignee(WorkitemTarget):
26
27 def __init__(self, name, url, complexity=0, todo_wis=[],
28@@ -90,6 +91,19 @@
29 return any([g.priority for g in self.groups])
30
31
32+class Workitem(object):
33+
34+ def __init__(self, description, status, blueprint, assignee=None):
35+ self.description = description
36+ self.status = status
37+ self.blueprint = blueprint
38+ self._assignee = assignee
39+
40+ @property
41+ def assignee(self):
42+ return self._assignee or self.blueprint.assignee
43+
44+
45 def spec_group_completion(db, team, milestone):
46 data = report_tools.spec_group_completion(db, team, milestone)
47 if not data:
48@@ -286,6 +300,21 @@
49 return group
50
51
52+def workitems_in_status(db, status, team=None, milestone=None):
53+ data = report_tools.assignee_completion(
54+ db, team=team, milestone=milestone)
55+ workitems = []
56+ for assignee in data:
57+ if status in data[assignee]:
58+ for wi_info in data[assignee][status]:
59+ bp_name, description, priority, url = wi_info
60+ blueprint = Blueprint(bp_name, url, priority=priority)
61+ workitems.append(
62+ Workitem(description, status, blueprint,
63+ assignee=assignee))
64+ return workitems
65+
66+
67 def list_people(db, team=None):
68 team_info = report_tools.team_information(db, team=team)
69 if team is None:
70@@ -398,6 +427,17 @@
71 data.update(dict(page_type="about"))
72 print report_tools.fill_template("about.html", data)
73
74+ def workitem_list(self, db, opts):
75+ assert opts.status is not None, (
76+ "Must pass --status for workitem_list report-type")
77+ workitems = workitems_in_status(
78+ db, opts.status, team=opts.team, milestone=opts.milestone)
79+ data = self.template_data(db, opts)
80+ data.update(dict(status=opts.status))
81+ data.update(dict(workitems=workitems))
82+ data.update(dict(page_type="overview"))
83+ print report_tools.fill_template("workitem_list.html", data)
84+
85
86 #
87 # main
88@@ -426,6 +466,8 @@
89 help="Select the group for a group_overview report.")
90 optparser.add_option('--root', dest="root",
91 help="Root URL for the charts")
92+ optparser.add_option('--status', dest="status",
93+ help="Workitem status to consider for workitem_list report-type")
94
95 (opts, args) = optparser.parse_args()
96 if not opts.database:
97
98=== modified file 'report_tools.py'
99--- report_tools.py 2011-02-24 01:33:40 +0000
100+++ report_tools.py 2011-02-26 01:02:30 +0000
101@@ -76,6 +76,25 @@
102 proc.wait()
103
104
105+def workitem_list(my_path, database, basename, config, status, root=None):
106+ cfg = load_config(config)
107+ team = cfg.get("primary_team", None)
108+ fh = open(basename + '.html', 'w')
109+ chartname = os.path.basename(basename)
110+ try:
111+ args = [os.path.join(my_path, 'html-report'), '-d', database, '--chart', '%s.svg' % chartname]
112+ args += ['--report-type', 'group_overview']
113+ args += ['--status', status]
114+ if root:
115+ args += ['--root', root]
116+ report_args(args, team=team)
117+ proc = Popen(args, stdout=fh)
118+ print basename + '.html'
119+ proc.wait()
120+ finally:
121+ fh.close()
122+
123+
124 def team_list_page(my_path, database, basename, config, root=None):
125 cfg = load_config(config)
126 team = cfg.get("primary_team", None)
127
128=== modified file 'templates/base.html'
129--- templates/base.html 2011-02-25 23:03:45 +0000
130+++ templates/base.html 2011-02-26 01:02:30 +0000
131@@ -19,11 +19,11 @@
132 td.priority_Essential, th.priority_Essential { color: red; }
133 td span.implementation_status { font-size: 70%; }
134
135- .status-todo {color: orange;}
136- .status-inprogress {color: gray;}
137- .status-done {color: green;}
138- .status-blocked {color: red;}
139- .status-postponed {color: purple;}
140+ .status-todo a {color: orange;}
141+ .status-inprogress a {color: gray;}
142+ .status-done a {color: green;}
143+ .status-blocked a {color: red;}
144+ .status-postponed a {color: purple;}
145
146 .interesting {
147 font-weight: bold;
148@@ -340,6 +340,13 @@
149 }
150 });
151
152+ $(".workitems_in_status").tablesorter({
153+ sortList: [[1,1],[0,0],[2,0]],
154+ headers: {
155+ 1: { sorter:'priority' }
156+ }
157+ });
158+
159 // with the 'todo/done' and assignee not appearing on every
160 // row, this does not lend itself well to sorting
161 //$("#byworkitem").tablesorter();
162
163=== modified file 'templates/overview.html'
164--- templates/overview.html 2011-02-16 21:53:06 +0000
165+++ templates/overview.html 2011-02-26 01:02:30 +0000
166@@ -44,26 +44,12 @@
167 <th>Count</th>
168 </tr>
169 </thead>
170-<tr class="status-todo">
171- <td>Todo</td>
172- <td>${all_workitems.todo}</td>
173-</tr>
174-<tr class="status-blocked">
175- <td>Blocked</td>
176- <td>${all_workitems.blocked}</td>
177-</tr>
178-<tr class="status-inprogress">
179- <td>In Progress</td>
180- <td>${all_workitems.inprogress}</td>
181-</tr>
182-<tr class="status-done">
183- <td>Done</td>
184- <td>${all_workitems.done}</td>
185-</tr>
186-<tr class="status-postponed">
187- <td>Postponed</td>
188- <td>${all_workitems.postponed}</td>
189-</tr>
190+% for status, label in [('todo', 'Todo'), ('blocked', 'Blocked'), ('inprogress', 'In Progress'), ('done', 'Done'), ('postponed', 'Postponed')]:
191+<tr class="status-${status}">
192+ <td><a href="${base.url(status + '.html')}">${label}</a></td>
193+ <td><a href="${base.url(status + '.html')}">${getattr(all_workitems,status)}</a></td>
194+</tr>
195+% endfor
196 </table>
197 <%def name="workitems_per_day(workitems, days)">
198 % if days < 1:
199
200=== added file 'templates/workitem_list.html'
201--- templates/workitem_list.html 1970-01-01 00:00:00 +0000
202+++ templates/workitem_list.html 2011-02-26 01:02:30 +0000
203@@ -0,0 +1,29 @@
204+<%inherit file="base.html"/>
205+<%namespace name="base" file="base.html"/>
206+
207+<%def name="title()">
208+Work items in ${status} status
209+</%def>
210+
211+<h1>Work items in ${status} status</h1>
212+
213+<p>This page shows the full list of workitems in a particular status. This can be useful to see a list of workitems that are blocked or postponed for instance.</p>
214+
215+<table class="workitems_in_status">
216+ <thead>
217+ <tr>
218+ <th>Blueprint</th>
219+ <th>Priority</th>
220+ <th>Assignee</th>
221+ <th>Description</th>
222+ </tr>
223+ </thead>
224+% for workitem in workitems:
225+ <tr>
226+ <td><a href="{workitem.blueprint.url}">${workitem.blueprint.name}</a></td>
227+ <td class="priority_${workitem.blueprint.priority}">${workitem.blueprint.priority}</td>
228+ <td>${base.real_name(workitem.assignee)}</td>
229+ <td>${workitem.description}</td>
230+ </tr>
231+% endfor
232+</table>

Subscribers

People subscribed via source and target branches

to all changes: