Merge lp:~jkakar/kanban/optional-needs-testing into lp:kanban
- optional-needs-testing
- Merge into trunk
Proposed by
Jamu Kakar
Status: | Merged |
---|---|
Approved by: | Martin Pool |
Approved revision: | 28 |
Merged at revision: | 24 |
Proposed branch: | lp:~jkakar/kanban/optional-needs-testing |
Merge into: | lp:kanban |
Diff against target: |
555 lines (+246/-39) 6 files modified
kanban/board.py (+28/-8) kanban/commands.py (+14/-6) kanban/templates/kanban.html (+88/-2) kanban/tests/test_board.py (+35/-16) media/decogrids-10.css (+74/-0) media/decogrids-12.css (+7/-7) |
To merge this branch: | bzr merge lp:~jkakar/kanban/optional-needs-testing |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Pool | Approve | ||
Review via email: mp+53119@code.launchpad.net |
Commit message
Description of the change
This branch introduces the following changes:
- The 'generate-
commands both take an optional --include-
The 'Needs testing' category is disabled by default, and only
displayed when this argument is provided.
- A new 10-column grid CSS file is available, and is used when the
'Needs testing' category is disabled.
To post a comment you must log in.
- 28. By Jamu Kakar
-
- Improved help text when 'Needs testing' is disabled.
Revision history for this message
Martin Pool (mbp) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'kanban/board.py' | |||
2 | --- kanban/board.py 2011-02-17 10:07:00 +0000 | |||
3 | +++ kanban/board.py 2011-03-12 20:16:43 +0000 | |||
4 | @@ -126,10 +126,16 @@ | |||
5 | 126 | 126 | ||
6 | 127 | 127 | ||
7 | 128 | class BugCollectionMixin(object): | 128 | class BugCollectionMixin(object): |
11 | 129 | """A named collecton of L{Bug}s organized into categories.""" | 129 | """A named collecton of L{Bug}s organized into categories. |
12 | 130 | 130 | ||
13 | 131 | def __init__(self, name): | 131 | @param name: The name of the L{Bug} collection. |
14 | 132 | @param include_needs_testing: Optionally, a flag indicating whether or not | ||
15 | 133 | to use the 'Needs testing' category. Defaults to C{False}. | ||
16 | 134 | """ | ||
17 | 135 | |||
18 | 136 | def __init__(self, name, include_needs_testing=False): | ||
19 | 132 | self.name = name | 137 | self.name = name |
20 | 138 | self.include_needs_testing = include_needs_testing | ||
21 | 133 | self.bugs = [] | 139 | self.bugs = [] |
22 | 134 | self.queued = [] | 140 | self.queued = [] |
23 | 135 | self.in_progress = [] | 141 | self.in_progress = [] |
24 | @@ -146,7 +152,10 @@ | |||
25 | 146 | elif bug.needs_release(): | 152 | elif bug.needs_release(): |
26 | 147 | self.needs_release.append(bug) | 153 | self.needs_release.append(bug) |
27 | 148 | elif bug.needs_testing(): | 154 | elif bug.needs_testing(): |
29 | 149 | self.needs_testing.append(bug) | 155 | if self.include_needs_testing: |
30 | 156 | self.needs_testing.append(bug) | ||
31 | 157 | else: | ||
32 | 158 | self.needs_release.append(bug) | ||
33 | 150 | elif bug.needs_review(): | 159 | elif bug.needs_review(): |
34 | 151 | self.needs_review.append(bug) | 160 | self.needs_review.append(bug) |
35 | 152 | elif bug.in_progress(): | 161 | elif bug.in_progress(): |
36 | @@ -159,6 +168,8 @@ | |||
37 | 159 | """A story is a collection of L{Bug}s related to a particular feature. | 168 | """A story is a collection of L{Bug}s related to a particular feature. |
38 | 160 | 169 | ||
39 | 161 | @param name: The name of this story. | 170 | @param name: The name of this story. |
40 | 171 | @param include_needs_testing: Optionally, a flag indicating whether or not | ||
41 | 172 | to use the 'Needs testing' category. Defaults to C{False}. | ||
42 | 162 | """ | 173 | """ |
43 | 163 | 174 | ||
44 | 164 | 175 | ||
45 | @@ -166,10 +177,13 @@ | |||
46 | 166 | """A collection of L{Bug}s grouped into L{Story}s. | 177 | """A collection of L{Bug}s grouped into L{Story}s. |
47 | 167 | 178 | ||
48 | 168 | @param name: The name of this collection. | 179 | @param name: The name of this collection. |
49 | 180 | @param include_needs_testing: Optionally, a flag indicating whether or not | ||
50 | 181 | to use the 'Needs testing' category. Defaults to C{False}. | ||
51 | 169 | """ | 182 | """ |
52 | 170 | 183 | ||
55 | 171 | def __init__(self, name): | 184 | def __init__(self, name, include_needs_testing=None): |
56 | 172 | super(StoryCollectionMixin, self).__init__(name) | 185 | super(StoryCollectionMixin, self).__init__( |
57 | 186 | name, include_needs_testing=include_needs_testing) | ||
58 | 173 | self._stories = {} | 187 | self._stories = {} |
59 | 174 | 188 | ||
60 | 175 | @property | 189 | @property |
61 | @@ -213,10 +227,14 @@ | |||
62 | 213 | @param project_name: The name of the project or project group in Launchpad | 227 | @param project_name: The name of the project or project group in Launchpad |
63 | 214 | this milestone is part of. | 228 | this milestone is part of. |
64 | 215 | @param milestone_name: The name of this milestone. | 229 | @param milestone_name: The name of this milestone. |
65 | 230 | @param include_needs_testing: Optionally, a flag indicating whether or not | ||
66 | 231 | to use the 'Needs testing' category. Defaults to C{False}. | ||
67 | 216 | """ | 232 | """ |
68 | 217 | 233 | ||
71 | 218 | def __init__(self, project_name, milestone_name): | 234 | def __init__(self, project_name, milestone_name, |
72 | 219 | super(MilestoneBoard, self).__init__(milestone_name) | 235 | include_needs_testing=None): |
73 | 236 | super(MilestoneBoard, self).__init__( | ||
74 | 237 | milestone_name, include_needs_testing=include_needs_testing) | ||
75 | 220 | self.project_name = project_name | 238 | self.project_name = project_name |
76 | 221 | 239 | ||
77 | 222 | 240 | ||
78 | @@ -226,6 +244,8 @@ | |||
79 | 226 | person or team. | 244 | person or team. |
80 | 227 | 245 | ||
81 | 228 | @param name: The name of the person or team. | 246 | @param name: The name of the person or team. |
82 | 247 | @param include_needs_testing: Optionally, a flag indicating whether or not | ||
83 | 248 | to use the 'Needs testing' category. Defaults to C{False}. | ||
84 | 229 | """ | 249 | """ |
85 | 230 | 250 | ||
86 | 231 | 251 | ||
87 | 232 | 252 | ||
88 | === modified file 'kanban/commands.py' | |||
89 | --- kanban/commands.py 2011-02-17 10:07:00 +0000 | |||
90 | +++ kanban/commands.py 2011-03-12 20:16:43 +0000 | |||
91 | @@ -57,12 +57,15 @@ | |||
92 | 57 | 57 | ||
93 | 58 | takes_args = ["person_name"] | 58 | takes_args = ["person_name"] |
94 | 59 | takes_options = [Option("output-file", short_name="o", type=str, | 59 | takes_options = [Option("output-file", short_name="o", type=str, |
96 | 60 | help="Write HTML to file.")] | 60 | help="Write HTML to file."), |
97 | 61 | Option("include-needs-testing", | ||
98 | 62 | help="Include the 'Needs testing' category.")] | ||
99 | 61 | _see_also = ["launchpad-login"] | 63 | _see_also = ["launchpad-login"] |
100 | 62 | 64 | ||
102 | 63 | def run(self, person_name, output_file=None): | 65 | def run(self, person_name, output_file=None, include_needs_testing=None): |
103 | 64 | launchpad = get_launchpad() | 66 | launchpad = get_launchpad() |
105 | 65 | person_board = PersonBoard(person_name) | 67 | person_board = PersonBoard(person_name, |
106 | 68 | include_needs_testing=include_needs_testing) | ||
107 | 66 | bugs = get_person_assigned_bugs(launchpad, person_name) | 69 | bugs = get_person_assigned_bugs(launchpad, person_name) |
108 | 67 | for bug in sorted(bugs, compare_bugs): | 70 | for bug in sorted(bugs, compare_bugs): |
109 | 68 | person_board.add(bug) | 71 | person_board.add(bug) |
110 | @@ -74,12 +77,17 @@ | |||
111 | 74 | 77 | ||
112 | 75 | takes_args = ["project_group", "milestone_name"] | 78 | takes_args = ["project_group", "milestone_name"] |
113 | 76 | takes_options = [Option("output-file", short_name="o", type=str, | 79 | takes_options = [Option("output-file", short_name="o", type=str, |
115 | 77 | help="Write HTML to file.")] | 80 | help="Write HTML to file."), |
116 | 81 | Option("include-needs-testing", | ||
117 | 82 | help="Include the 'Needs testing' category.")] | ||
118 | 78 | _see_also = ["launchpad-login"] | 83 | _see_also = ["launchpad-login"] |
119 | 79 | 84 | ||
121 | 80 | def run(self, project_group, milestone_name, output_file=None): | 85 | def run(self, project_group, milestone_name, output_file=None, |
122 | 86 | include_needs_testing=None): | ||
123 | 81 | launchpad = get_launchpad() | 87 | launchpad = get_launchpad() |
125 | 82 | milestone_board = MilestoneBoard(project_group, milestone_name) | 88 | milestone_board = MilestoneBoard( |
126 | 89 | project_group, milestone_name, | ||
127 | 90 | include_needs_testing=include_needs_testing) | ||
128 | 83 | bugs = get_milestone_bugs(launchpad, project_group, milestone_name) | 91 | bugs = get_milestone_bugs(launchpad, project_group, milestone_name) |
129 | 84 | for bug in sorted(bugs, compare_bugs): | 92 | for bug in sorted(bugs, compare_bugs): |
130 | 85 | milestone_board.add(bug) | 93 | milestone_board.add(bug) |
131 | 86 | 94 | ||
132 | === modified file 'kanban/templates/kanban.html' | |||
133 | --- kanban/templates/kanban.html 2011-02-17 10:07:00 +0000 | |||
134 | +++ kanban/templates/kanban.html 2011-03-12 20:16:43 +0000 | |||
135 | @@ -1,14 +1,22 @@ | |||
136 | 1 | <html> | 1 | <html> |
137 | 2 | <head> | 2 | <head> |
138 | 3 | <title>{{ kanban_board.project_name }} {{ kanban_board.name }}</title> | 3 | <title>{{ kanban_board.project_name }} {{ kanban_board.name }}</title> |
139 | 4 | {% if kanban_board.include_needs_testing %} | ||
140 | 4 | <link rel="stylesheet" type="text/css" href="media/decogrids-12.css" /> | 5 | <link rel="stylesheet" type="text/css" href="media/decogrids-12.css" /> |
141 | 6 | {% else %} | ||
142 | 7 | <link rel="stylesheet" type="text/css" href="media/decogrids-10.css" /> | ||
143 | 8 | {% endif %} | ||
144 | 5 | <link rel="stylesheet" type="text/css" href="media/kanban.css" /> | 9 | <link rel="stylesheet" type="text/css" href="media/kanban.css" /> |
145 | 6 | </head> | 10 | </head> |
146 | 7 | 11 | ||
147 | 8 | <body> | 12 | <body> |
148 | 9 | <div id="container"> | 13 | <div id="container"> |
149 | 10 | <div id="heading" class="row"> | 14 | <div id="heading" class="row"> |
150 | 15 | {% if kanban_board.include_needs_testing %} | ||
151 | 11 | <div class="position-0 width-12 cell"> | 16 | <div class="position-0 width-12 cell"> |
152 | 17 | {% else %} | ||
153 | 18 | <div class="position-0 width-10 cell"> | ||
154 | 19 | {% endif %} | ||
155 | 12 | {% if is_milestone %} | 20 | {% if is_milestone %} |
156 | 13 | <h1><a href="https://launchpad.net/{{ kanban_board.project_name }}">{{ kanban_board.project_name }}</a> <a href="https://launchpad.net/{{ kanban_board.project_name }}/+milestone/{{ kanban_board.name}}">{{ kanban_board.name }}</a> <span class="bug-count">{{ kanban_board.bugs|length }} bugs</span></h1> | 21 | <h1><a href="https://launchpad.net/{{ kanban_board.project_name }}">{{ kanban_board.project_name }}</a> <a href="https://launchpad.net/{{ kanban_board.project_name }}/+milestone/{{ kanban_board.name}}">{{ kanban_board.name }}</a> <span class="bug-count">{{ kanban_board.bugs|length }} bugs</span></h1> |
157 | 14 | {% else %} | 22 | {% else %} |
158 | @@ -21,17 +29,30 @@ | |||
159 | 21 | <div class="position-0 width-2 cell"><h2>Queued <span class="bug-count">{{ kanban_board.queued|length }} bugs</span></h2></div> | 29 | <div class="position-0 width-2 cell"><h2>Queued <span class="bug-count">{{ kanban_board.queued|length }} bugs</span></h2></div> |
160 | 22 | <div class="position-2 width-2 cell"><h2>In progress <span class="bug-count">{{ kanban_board.in_progress|length }} bugs</span></h2></div> | 30 | <div class="position-2 width-2 cell"><h2>In progress <span class="bug-count">{{ kanban_board.in_progress|length }} bugs</span></h2></div> |
161 | 23 | <div class="position-4 width-2 cell"><h2>Needs review <span class="bug-count">{{ kanban_board.needs_review|length }} bugs</span></h2></div> | 31 | <div class="position-4 width-2 cell"><h2>Needs review <span class="bug-count">{{ kanban_board.needs_review|length }} bugs</span></h2></div> |
162 | 32 | {% if kanban_board.include_needs_testing %} | ||
163 | 24 | <div class="position-6 width-2 cell"><h2>Needs testing <span class="bug-count">{{ kanban_board.needs_testing|length }} bugs</span></h2></div> | 33 | <div class="position-6 width-2 cell"><h2>Needs testing <span class="bug-count">{{ kanban_board.needs_testing|length }} bugs</span></h2></div> |
164 | 25 | <div class="position-8 width-2 cell"><h2>Needs release <span class="bug-count">{{ kanban_board.needs_release|length }} bugs</span></h2></div> | 34 | <div class="position-8 width-2 cell"><h2>Needs release <span class="bug-count">{{ kanban_board.needs_release|length }} bugs</span></h2></div> |
165 | 26 | <div class="position-10 width-2 cell"><h2>Released <span class="bug-count">{{ kanban_board.released|length }} bugs</span></h2></div> | 35 | <div class="position-10 width-2 cell"><h2>Released <span class="bug-count">{{ kanban_board.released|length }} bugs</span></h2></div> |
166 | 36 | {% else %} | ||
167 | 37 | <div class="position-6 width-2 cell"><h2>Needs release <span class="bug-count">{{ kanban_board.needs_release|length }} bugs</span></h2></div> | ||
168 | 38 | <div class="position-8 width-2 cell"><h2>Released <span class="bug-count">{{ kanban_board.released|length }} bugs</span></h2></div> | ||
169 | 39 | {% endif %} | ||
170 | 27 | </div> | 40 | </div> |
171 | 28 | 41 | ||
172 | 29 | {% for story in kanban_board.stories %} | 42 | {% for story in kanban_board.stories %} |
173 | 30 | <div class="tiles row story"> | 43 | <div class="tiles row story"> |
174 | 31 | {% if story.name %} | 44 | {% if story.name %} |
176 | 32 | <div class="position-0 width-12 cell">{{ story.name }}</div> | 45 | {% if kanban_board.include_needs_testing %} |
177 | 46 | <div class="position-0 width-12 cell">{{ story.name }}</div> | ||
178 | 47 | {% else %} | ||
179 | 48 | <div class="position-0 width-10 cell">{{ story.name }}</div> | ||
180 | 49 | {% endif %} | ||
181 | 33 | {% else %} | 50 | {% else %} |
183 | 34 | <div class="position-0 width-12 cell">uncategorized</div> | 51 | {% if kanban_board.include_needs_testing %} |
184 | 52 | <div class="position-0 width-12 cell">uncategorized</div> | ||
185 | 53 | {% else %} | ||
186 | 54 | <div class="position-0 width-10 cell">uncategorized</div> | ||
187 | 55 | {% endif %} | ||
188 | 35 | {% endif %} | 56 | {% endif %} |
189 | 36 | </div> | 57 | </div> |
190 | 37 | 58 | ||
191 | @@ -115,6 +136,7 @@ | |||
192 | 115 | 136 | ||
193 | 116 | </div> | 137 | </div> |
194 | 117 | 138 | ||
195 | 139 | {% if kanban_board.include_needs_testing %} | ||
196 | 118 | <div class="position-6 width-2 cell"> | 140 | <div class="position-6 width-2 cell"> |
197 | 119 | 141 | ||
198 | 120 | {% for bug in story.needs_testing %} | 142 | {% for bug in story.needs_testing %} |
199 | @@ -171,6 +193,45 @@ | |||
200 | 171 | {% endfor %} | 193 | {% endfor %} |
201 | 172 | 194 | ||
202 | 173 | </div> | 195 | </div> |
203 | 196 | {% else %} | ||
204 | 197 | <div class="position-6 width-2 cell"> | ||
205 | 198 | |||
206 | 199 | {% for bug in story.needs_release %} | ||
207 | 200 | <div class="tile"> | ||
208 | 201 | {% if bug.assignee %} | ||
209 | 202 | <span class="assignee">{{ bug.assignee }}</span> | ||
210 | 203 | {% endif %} | ||
211 | 204 | <a href="https://bugs.launchpad.net/bugs/{{ bug.id }}">#{{ bug.id }}</a> <span class="{{ bug.importance|importance_css_class }}">{{ bug.importance }}</span> | ||
212 | 205 | <br/> | ||
213 | 206 | <div class="project">{{ bug.project }}</div> | ||
214 | 207 | <div>{{ bug.title }}</div> | ||
215 | 208 | {% if bug.branch %} | ||
216 | 209 | <div class="merge-proposal"><a href="{{ bug|branch_url }}">{{ bug.branch|branch_name }}</a></div> | ||
217 | 210 | {% endif %} | ||
218 | 211 | </div> | ||
219 | 212 | {% endfor %} | ||
220 | 213 | |||
221 | 214 | </div> | ||
222 | 215 | |||
223 | 216 | <div class="position-8 width-2 cell"> | ||
224 | 217 | |||
225 | 218 | {% for bug in story.released %} | ||
226 | 219 | <div class="tile"> | ||
227 | 220 | {% if bug.assignee %} | ||
228 | 221 | <span class="assignee">{{ bug.assignee }}</span> | ||
229 | 222 | {% endif %} | ||
230 | 223 | <a href="https://bugs.launchpad.net/bugs/{{ bug.id }}">#{{ bug.id }}</a> <span class="{{ bug.importance|importance_css_class }}">{{ bug.importance }}</span> | ||
231 | 224 | <br/> | ||
232 | 225 | <div class="project">{{ bug.project }}</div> | ||
233 | 226 | <div>{{ bug.title }}</div> | ||
234 | 227 | {% if bug.branch %} | ||
235 | 228 | <div class="merge-proposal"><a href="{{ bug|branch_url }}">{{ bug.branch|branch_name }}</a></div> | ||
236 | 229 | {% endif %} | ||
237 | 230 | </div> | ||
238 | 231 | {% endfor %} | ||
239 | 232 | |||
240 | 233 | </div> | ||
241 | 234 | {% endif %} | ||
242 | 174 | </div> | 235 | </div> |
243 | 175 | {% endfor %} | 236 | {% endfor %} |
244 | 176 | 237 | ||
245 | @@ -195,6 +256,7 @@ | |||
246 | 195 | </div> | 256 | </div> |
247 | 196 | </div> | 257 | </div> |
248 | 197 | 258 | ||
249 | 259 | {% if kanban_board.include_needs_testing %} | ||
250 | 198 | <div class="position-6 width-2 cell"> | 260 | <div class="position-6 width-2 cell"> |
251 | 199 | <div class="legend-description"> | 261 | <div class="legend-description"> |
252 | 200 | <strong>Needs testing</strong> bugs are <em>Fix Committed</em> | 262 | <strong>Needs testing</strong> bugs are <em>Fix Committed</em> |
253 | @@ -215,16 +277,40 @@ | |||
254 | 215 | <strong>Fix released</strong> bugs are <em>Fix Released</em>. | 277 | <strong>Fix released</strong> bugs are <em>Fix Released</em>. |
255 | 216 | </div> | 278 | </div> |
256 | 217 | </div> | 279 | </div> |
257 | 280 | {% else %} | ||
258 | 281 | <div class="position-6 width-2 cell"> | ||
259 | 282 | <div class="legend-description"> | ||
260 | 283 | <strong>Needs release</strong> bugs are <em>Fix | ||
261 | 284 | Committed</em> or <em>In Progress</em> with | ||
262 | 285 | an <em>Approved</em> or | ||
263 | 286 | <em>Merged</em> merge proposal. | ||
264 | 287 | </div> | ||
265 | 288 | </div> | ||
266 | 289 | |||
267 | 290 | <div class="position-8 width-2 cell"> | ||
268 | 291 | <div class="legend-description"> | ||
269 | 292 | <strong>Fix released</strong> bugs are <em>Fix Released</em>. | ||
270 | 293 | </div> | ||
271 | 294 | </div> | ||
272 | 295 | {% endif %} | ||
273 | 218 | </div> | 296 | </div> |
274 | 219 | 297 | ||
275 | 220 | <!-- XXX This is a hack. It'd be better to add bottom-rounded | 298 | <!-- XXX This is a hack. It'd be better to add bottom-rounded |
276 | 221 | borders to the last .tile element. --> | 299 | borders to the last .tile element. --> |
277 | 222 | <div id="prefooter" class="row"> | 300 | <div id="prefooter" class="row"> |
278 | 301 | {% if kanban_board.include_needs_testing %} | ||
279 | 223 | <div class="position-0 width-12 cell"> </div> | 302 | <div class="position-0 width-12 cell"> </div> |
280 | 303 | {% else %} | ||
281 | 304 | <div class="position-0 width-10 cell"> </div> | ||
282 | 305 | {% endif %} | ||
283 | 224 | </div> | 306 | </div> |
284 | 225 | 307 | ||
285 | 226 | <div id="footer" class="row"> | 308 | <div id="footer" class="row"> |
286 | 309 | {% if kanban_board.include_needs_testing %} | ||
287 | 227 | <div class="position-0 width-12 cell">Generated on {{ now }}.</div> | 310 | <div class="position-0 width-12 cell">Generated on {{ now }}.</div> |
288 | 311 | {% else %} | ||
289 | 312 | <div class="position-0 width-10 cell">Generated on {{ now }}.</div> | ||
290 | 313 | {% endif %} | ||
291 | 228 | </div> | 314 | </div> |
292 | 229 | 315 | ||
293 | 230 | </div> | 316 | </div> |
294 | 231 | 317 | ||
295 | === modified file 'kanban/tests/test_board.py' | |||
296 | --- kanban/tests/test_board.py 2011-02-17 10:07:00 +0000 | |||
297 | +++ kanban/tests/test_board.py 2011-03-12 20:16:43 +0000 | |||
298 | @@ -278,8 +278,8 @@ | |||
299 | 278 | def test_add_queued(self): | 278 | def test_add_queued(self): |
300 | 279 | """ | 279 | """ |
301 | 280 | A L{Bug} in the 'Queued' category is stored in the | 280 | A L{Bug} in the 'Queued' category is stored in the |
304 | 281 | L{BugCollectionMixin.bugs} and the L{Story.queued} list in the default | 281 | L{BugCollectionMixin.bugs} and the L{Story.queued} lists, in the |
305 | 282 | story. | 282 | default story. |
306 | 283 | """ | 283 | """ |
307 | 284 | bug = Bug("1", "kanban", MEDIUM, NEW, "A title") | 284 | bug = Bug("1", "kanban", MEDIUM, NEW, "A title") |
308 | 285 | kanban_board = self.create_test_class() | 285 | kanban_board = self.create_test_class() |
309 | @@ -295,7 +295,7 @@ | |||
310 | 295 | def test_add_in_progress(self): | 295 | def test_add_in_progress(self): |
311 | 296 | """ | 296 | """ |
312 | 297 | A L{Bug} in the 'In progress' category is stored in the | 297 | A L{Bug} in the 'In progress' category is stored in the |
314 | 298 | L{BugCollectionMixin.bugs} and the L{Story.in_progress} list in the | 298 | L{BugCollectionMixin.bugs} and the L{Story.in_progress} lists, in the |
315 | 299 | default story. | 299 | default story. |
316 | 300 | """ | 300 | """ |
317 | 301 | bug = Bug("1", "kanban", MEDIUM, IN_PROGRESS, "A title") | 301 | bug = Bug("1", "kanban", MEDIUM, IN_PROGRESS, "A title") |
318 | @@ -312,7 +312,7 @@ | |||
319 | 312 | def test_add_needs_review(self): | 312 | def test_add_needs_review(self): |
320 | 313 | """ | 313 | """ |
321 | 314 | A L{Bug} in the 'Needs review' category is stored in the | 314 | A L{Bug} in the 'Needs review' category is stored in the |
323 | 315 | L{BugCollectionMixin.bugs} and the L{Story.in_progress} list in the | 315 | L{BugCollectionMixin.bugs} and the L{Story.in_progress} lists, in the |
324 | 316 | default story. | 316 | default story. |
325 | 317 | """ | 317 | """ |
326 | 318 | bug = Bug("1", "kanban", MEDIUM, IN_PROGRESS, "A title", | 318 | bug = Bug("1", "kanban", MEDIUM, IN_PROGRESS, "A title", |
327 | @@ -330,12 +330,12 @@ | |||
328 | 330 | def test_add_needs_testing(self): | 330 | def test_add_needs_testing(self): |
329 | 331 | """ | 331 | """ |
330 | 332 | A L{Bug} in the 'Needs testing' category is stored in the | 332 | A L{Bug} in the 'Needs testing' category is stored in the |
333 | 333 | L{BugCollectionMixin.bugs} and the L{Story.needs_testing} list in the | 333 | L{BugCollectionMixin.bugs} and the L{Story.needs_testing} lists, in |
334 | 334 | default story. | 334 | the default story. |
335 | 335 | """ | 335 | """ |
336 | 336 | bug = Bug("1", "kanban", MEDIUM, IN_PROGRESS, "A title", | 336 | bug = Bug("1", "kanban", MEDIUM, IN_PROGRESS, "A title", |
337 | 337 | merge_proposal="url", merge_proposal_status=APPROVED) | 337 | merge_proposal="url", merge_proposal_status=APPROVED) |
339 | 338 | kanban_board = self.create_test_class() | 338 | kanban_board = self.create_test_class(include_needs_testing=True) |
340 | 339 | kanban_board.add(bug) | 339 | kanban_board.add(bug) |
341 | 340 | self.assertEqual([bug], kanban_board.bugs) | 340 | self.assertEqual([bug], kanban_board.bugs) |
342 | 341 | self.assertEqual([], kanban_board.queued) | 341 | self.assertEqual([], kanban_board.queued) |
343 | @@ -345,11 +345,29 @@ | |||
344 | 345 | self.assertEqual([], kanban_board.needs_release) | 345 | self.assertEqual([], kanban_board.needs_release) |
345 | 346 | self.assertEqual([], kanban_board.released) | 346 | self.assertEqual([], kanban_board.released) |
346 | 347 | 347 | ||
347 | 348 | def test_add_needs_testing_disabled(self): | ||
348 | 349 | """ | ||
349 | 350 | A L{Bug} in the 'Needs testing' category is stored in the | ||
350 | 351 | L{BugCollectionMixin.bugs} and the L{Story.needs_release} lists, in | ||
351 | 352 | the default story, when the 'Needs testing' category is disabled. | ||
352 | 353 | """ | ||
353 | 354 | bug = Bug("1", "kanban", MEDIUM, IN_PROGRESS, "A title", | ||
354 | 355 | merge_proposal="url", merge_proposal_status=APPROVED) | ||
355 | 356 | kanban_board = self.create_test_class() | ||
356 | 357 | kanban_board.add(bug) | ||
357 | 358 | self.assertEqual([bug], kanban_board.bugs) | ||
358 | 359 | self.assertEqual([], kanban_board.queued) | ||
359 | 360 | self.assertEqual([], kanban_board.in_progress) | ||
360 | 361 | self.assertEqual([], kanban_board.needs_review) | ||
361 | 362 | self.assertEqual([], kanban_board.needs_testing) | ||
362 | 363 | self.assertEqual([bug], kanban_board.needs_release) | ||
363 | 364 | self.assertEqual([], kanban_board.released) | ||
364 | 365 | |||
365 | 348 | def test_add_needs_release(self): | 366 | def test_add_needs_release(self): |
366 | 349 | """ | 367 | """ |
367 | 350 | A L{Bug} in the 'Needs release' category is stored in the | 368 | A L{Bug} in the 'Needs release' category is stored in the |
370 | 351 | L{BugCollectionMixin.bugs} and the L{Story.needs_release} list in the | 369 | L{BugCollectionMixin.bugs} and the L{Story.needs_release} lists, in |
371 | 352 | default story. | 370 | the default story. |
372 | 353 | """ | 371 | """ |
373 | 354 | bug = Bug("1", "kanban", MEDIUM, FIX_COMMITTED, "A title", | 372 | bug = Bug("1", "kanban", MEDIUM, FIX_COMMITTED, "A title", |
374 | 355 | merge_proposal="url", merge_proposal_status=MERGED, | 373 | merge_proposal="url", merge_proposal_status=MERGED, |
375 | @@ -367,7 +385,7 @@ | |||
376 | 367 | def test_add_released(self): | 385 | def test_add_released(self): |
377 | 368 | """ | 386 | """ |
378 | 369 | A L{Bug} in the 'Released' category is stored in the | 387 | A L{Bug} in the 'Released' category is stored in the |
380 | 370 | L{BugCollectionMixin.bugs} and the L{Story.released} list in the | 388 | L{BugCollectionMixin.bugs} and the L{Story.released} lists, in the |
381 | 371 | default story. | 389 | default story. |
382 | 372 | """ | 390 | """ |
383 | 373 | bug = Bug("1", "kanban", MEDIUM, FIX_RELEASED, "A title") | 391 | bug = Bug("1", "kanban", MEDIUM, FIX_RELEASED, "A title") |
384 | @@ -463,12 +481,13 @@ | |||
385 | 463 | class MilestoneBoardTest(BugCollectionMixinTestBase, | 481 | class MilestoneBoardTest(BugCollectionMixinTestBase, |
386 | 464 | StoryCollectionMixinTestBase, TestCase): | 482 | StoryCollectionMixinTestBase, TestCase): |
387 | 465 | 483 | ||
389 | 466 | def create_test_class(self): | 484 | def create_test_class(self, include_needs_testing=None): |
390 | 467 | """ | 485 | """ |
391 | 468 | Create a L{MilestoneBoard} for use in L{BugCollectionMixinTestBase} | 486 | Create a L{MilestoneBoard} for use in L{BugCollectionMixinTestBase} |
392 | 469 | and L{StoryCollectionMixinTestBase} tests. | 487 | and L{StoryCollectionMixinTestBase} tests. |
393 | 470 | """ | 488 | """ |
395 | 471 | return MilestoneBoard("project", "milestone") | 489 | return MilestoneBoard("project", "milestone", |
396 | 490 | include_needs_testing=include_needs_testing) | ||
397 | 472 | 491 | ||
398 | 473 | def test_instantiate(self): | 492 | def test_instantiate(self): |
399 | 474 | """ | 493 | """ |
400 | @@ -484,12 +503,12 @@ | |||
401 | 484 | class PersonBoardTest(BugCollectionMixinTestBase, StoryCollectionMixinTestBase, | 503 | class PersonBoardTest(BugCollectionMixinTestBase, StoryCollectionMixinTestBase, |
402 | 485 | TestCase): | 504 | TestCase): |
403 | 486 | 505 | ||
405 | 487 | def create_test_class(self): | 506 | def create_test_class(self, include_needs_testing=None): |
406 | 488 | """ | 507 | """ |
407 | 489 | Create a L{PersonBoard} for use in L{BugCollectionMixinTestBase} and | 508 | Create a L{PersonBoard} for use in L{BugCollectionMixinTestBase} and |
408 | 490 | L{StoryCollectionMixinTestBase} tests. | 509 | L{StoryCollectionMixinTestBase} tests. |
409 | 491 | """ | 510 | """ |
411 | 492 | return PersonBoard("team") | 511 | return PersonBoard("team", include_needs_testing=include_needs_testing) |
412 | 493 | 512 | ||
413 | 494 | def test_instantiate(self): | 513 | def test_instantiate(self): |
414 | 495 | """ | 514 | """ |
415 | @@ -503,11 +522,11 @@ | |||
416 | 503 | 522 | ||
417 | 504 | class StoryTest(BugCollectionMixinTestBase, TestCase): | 523 | class StoryTest(BugCollectionMixinTestBase, TestCase): |
418 | 505 | 524 | ||
420 | 506 | def create_test_class(self): | 525 | def create_test_class(self, include_needs_testing=None): |
421 | 507 | """ | 526 | """ |
422 | 508 | Create a L{Story} for use in L{BugCollectionMixinTestBase} tests. | 527 | Create a L{Story} for use in L{BugCollectionMixinTestBase} tests. |
423 | 509 | """ | 528 | """ |
425 | 510 | return Story("name") | 529 | return Story("name", include_needs_testing=include_needs_testing) |
426 | 511 | 530 | ||
427 | 512 | 531 | ||
428 | 513 | class CompareStoriesTest(TestCase): | 532 | class CompareStoriesTest(TestCase): |
429 | 514 | 533 | ||
430 | === added file 'media/decogrids-10.css' | |||
431 | --- media/decogrids-10.css 1970-01-01 00:00:00 +0000 | |||
432 | +++ media/decogrids-10.css 2011-03-12 20:16:43 +0000 | |||
433 | @@ -0,0 +1,74 @@ | |||
434 | 1 | /* The 12-column Deco Grid System. | ||
435 | 2 | * Available in multiple variants, see http://deco.gs | ||
436 | 3 | * | ||
437 | 4 | * Cells are 7.91668% (=76px) | ||
438 | 5 | * Margins are 1.04166% (=10px) (times two, left and right) | ||
439 | 6 | * Total is 10% (=96px) (which makes 10 columns) | ||
440 | 7 | * | ||
441 | 8 | * If page width is fixed to 960px width: | ||
442 | 9 | * Cell will be equivalent to 76px, left/right margin will be 10px. | ||
443 | 10 | * | ||
444 | 11 | */ | ||
445 | 12 | |||
446 | 13 | div.row { | ||
447 | 14 | float: left; | ||
448 | 15 | width: 100%; | ||
449 | 16 | display: block; | ||
450 | 17 | position: relative; | ||
451 | 18 | } | ||
452 | 19 | div.cell { | ||
453 | 20 | position: relative; | ||
454 | 21 | float: left; | ||
455 | 22 | left: 100%; | ||
456 | 23 | } | ||
457 | 24 | |||
458 | 25 | /* Width classes. | ||
459 | 26 | For a given cell width, the calculation is: | ||
460 | 27 | width = (total cell width) * n - (margin*2) | ||
461 | 28 | In this case: (8.333*n - 2.08333)% */ | ||
462 | 29 | div.width-1 { width: 7.9166% } | ||
463 | 30 | div.width-2 { width: 17.916% } | ||
464 | 31 | div.width-3 { width: 27.916% } | ||
465 | 32 | div.width-4 { width: 37.916% } | ||
466 | 33 | div.width-5 { width: 47.916% } | ||
467 | 34 | div.width-6 { width: 57.916% } | ||
468 | 35 | div.width-7 { width: 67.916% } | ||
469 | 36 | div.width-8 { width: 77.916% } | ||
470 | 37 | div.width-9 { width: 87.916% } | ||
471 | 38 | div.width-10 { width: 97.916% } | ||
472 | 39 | |||
473 | 40 | |||
474 | 41 | |||
475 | 42 | /* Positioning classes, these are subtracting from a rightmost | ||
476 | 43 | position, which is why they seem the wrong way around */ | ||
477 | 44 | /* For a given position, the calculation is: | ||
478 | 45 | -100 + (total cell width * n) | ||
479 | 46 | In this case: margin-left: -100 + (8.333*n) */ | ||
480 | 47 | div.position-0 { margin-left: -100% } | ||
481 | 48 | div.position-1 { margin-left: -90% } | ||
482 | 49 | div.position-2 { margin-left: -80% } | ||
483 | 50 | div.position-3 { margin-left: -70% } | ||
484 | 51 | div.position-4 { margin-left: -60% } | ||
485 | 52 | div.position-5 { margin-left: -50% } | ||
486 | 53 | div.position-6 { margin-left: -40% } | ||
487 | 54 | div.position-7 { margin-left: -30% } | ||
488 | 55 | div.position-8 { margin-left: -20% } | ||
489 | 56 | div.position-9 { margin-left: -10% } | ||
490 | 57 | |||
491 | 58 | /* End of the core Deco Grid System */ | ||
492 | 59 | |||
493 | 60 | /* Convenience classes — ¼, ½, ¾ widths and ¼, ½, ¾ positions. | ||
494 | 61 | Not strictly necessary. */ | ||
495 | 62 | div.width-1\3a 2 { width: 47.916%; } /* .width-1:2 */ | ||
496 | 63 | div.width-1\3a 4 { width: 22.916%; } /* .width-1:4 */ | ||
497 | 64 | div.width-3\3a 4 { width: 72.916%; } /* .width-3:4 */ | ||
498 | 65 | div.position-1\3a 4 { margin-left: -75.001%;} /* .position-1:4 */ | ||
499 | 66 | div.position-1\3a 2 { margin-left: -50.002%;} /* .position-1:2 */ | ||
500 | 67 | div.position-3\3a 4 { margin-left: -25.003%;} /* .position-3:4 */ | ||
501 | 68 | |||
502 | 69 | |||
503 | 70 | /* Special classes for ⅓, ⅔ widths and ⅓, ⅔ positions. */ | ||
504 | 71 | div.width-1\3a 3 { width: 31.250%; } /* .width-1:3 */ | ||
505 | 72 | div.width-2\3a 3 { width: 64.583%; } /* .width-2:3 */ | ||
506 | 73 | div.position-1\3a 3 {margin-left: -66.668%;} /* .position-1:3 */ | ||
507 | 74 | div.position-2\3a 3 {margin-left: -33.336%;} /* .position-2:3 */ | ||
508 | 0 | 75 | ||
509 | === modified file 'media/decogrids-12.css' | |||
510 | --- media/decogrids-12.css 2010-11-15 00:00:59 +0000 | |||
511 | +++ media/decogrids-12.css 2011-03-12 20:16:43 +0000 | |||
512 | @@ -1,10 +1,10 @@ | |||
514 | 1 | /* The 12-column Deco Grid System. | 1 | /* The 12-column Deco Grid System. |
515 | 2 | * Available in multiple variants, see http://deco.gs | 2 | * Available in multiple variants, see http://deco.gs |
516 | 3 | * | 3 | * |
517 | 4 | * Cells are 6.25% (=60px) | 4 | * Cells are 6.25% (=60px) |
518 | 5 | * Margins are 1.04166% (=10px) (times two, left and right) | 5 | * Margins are 1.04166% (=10px) (times two, left and right) |
519 | 6 | * Total is 8.33333%. (=80px) (which makes 12 columns) | 6 | * Total is 8.33333%. (=80px) (which makes 12 columns) |
521 | 7 | * | 7 | * |
522 | 8 | * If page width is fixed to 960px width: | 8 | * If page width is fixed to 960px width: |
523 | 9 | * Cell will be equivalent to 60px, left/right margin will be 10px. | 9 | * Cell will be equivalent to 60px, left/right margin will be 10px. |
524 | 10 | * | 10 | * |
525 | @@ -22,9 +22,9 @@ | |||
526 | 22 | left: 100%; | 22 | left: 100%; |
527 | 23 | } | 23 | } |
528 | 24 | 24 | ||
532 | 25 | /* Width classes. | 25 | /* Width classes. |
533 | 26 | For a given cell width, the calculation is: | 26 | For a given cell width, the calculation is: |
534 | 27 | width = (total cell width) * n - (margin*2) | 27 | width = (total cell width) * n - (margin*2) |
535 | 28 | In this case: (8.333*n - 2.08333)% */ | 28 | In this case: (8.333*n - 2.08333)% */ |
536 | 29 | div.width-1 { width: 6.2500% } | 29 | div.width-1 { width: 6.2500% } |
537 | 30 | div.width-2 { width: 14.583% } | 30 | div.width-2 { width: 14.583% } |
538 | @@ -39,7 +39,7 @@ | |||
539 | 39 | div.width-11 { width: 89.583% } | 39 | div.width-11 { width: 89.583% } |
540 | 40 | div.width-12 { width: 97.916% } | 40 | div.width-12 { width: 97.916% } |
541 | 41 | 41 | ||
543 | 42 | /* Positioning classes, these are subtracting from a rightmost | 42 | /* Positioning classes, these are subtracting from a rightmost |
544 | 43 | position, which is why they seem the wrong way around */ | 43 | position, which is why they seem the wrong way around */ |
545 | 44 | /* For a given position, the calculation is: | 44 | /* For a given position, the calculation is: |
546 | 45 | -100 + (total cell width * n) | 45 | -100 + (total cell width * n) |
547 | @@ -59,7 +59,7 @@ | |||
548 | 59 | 59 | ||
549 | 60 | /* End of the core Deco Grid System */ | 60 | /* End of the core Deco Grid System */ |
550 | 61 | 61 | ||
552 | 62 | /* Convenience classes — ¼, ½, ¾ widths and ¼, ½, ¾ positions. | 62 | /* Convenience classes — ¼, ½, ¾ widths and ¼, ½, ¾ positions. |
553 | 63 | Not strictly necessary. */ | 63 | Not strictly necessary. */ |
554 | 64 | div.width-1\3a 2 { width: 47.916%; } /* .width-1:2 */ | 64 | div.width-1\3a 2 { width: 47.916%; } /* .width-1:2 */ |
555 | 65 | div.width-1\3a 4 { width: 22.916%; } /* .width-1:4 */ | 65 | div.width-1\3a 4 { width: 22.916%; } /* .width-1:4 */ |