Merge lp:~michael.nelson/launchpad/635005-difference-details-2 into lp:launchpad/db-devel
- 635005-difference-details-2
- Merge into db-devel
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Michael Nelson | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 9813 | ||||
Proposed branch: | lp:~michael.nelson/launchpad/635005-difference-details-2 | ||||
Merge into: | lp:launchpad/db-devel | ||||
Diff against target: |
958 lines (+452/-101) 21 files modified
lib/canonical/launchpad/interfaces/_schema_circular_imports.py (+4/-0) lib/lp/app/templates/base-layout-macros.pt (+2/-0) lib/lp/code/browser/branchmergeproposal.py (+9/-2) lib/lp/code/browser/codereviewcomment.py (+39/-35) lib/lp/code/browser/configure.zcml (+10/-3) lib/lp/code/browser/tests/test_branchmergeproposal.py (+21/-2) lib/lp/code/browser/tests/test_codereviewcomment.py (+26/-9) lib/lp/code/templates/codereviewcomment-body.pt (+2/-2) lib/lp/code/templates/codereviewcomment-header.pt (+3/-3) lib/lp/registry/browser/configure.zcml (+4/-1) lib/lp/registry/browser/distroseriesdifference.py (+40/-6) lib/lp/registry/browser/tests/test_distroseriesdifference_views.py (+58/-13) lib/lp/registry/browser/tests/test_series_views.py (+19/-0) lib/lp/registry/javascript/distroseriesdifferences_details.js (+86/-0) lib/lp/registry/templates/distroseries-localdifferences.pt (+9/-2) lib/lp/registry/templates/distroseriesdifference-listing-extra.pt (+31/-19) lib/lp/registry/windmill/tests/test_distroseriesdifference_expander.py (+42/-0) lib/lp/services/comments/browser/configure.zcml (+12/-4) lib/lp/services/comments/interfaces/conversation.py (+18/-0) lib/lp/services/comments/templates/comment-body.pt (+8/-0) lib/lp/services/comments/templates/comment-header.pt (+9/-0) |
||||
To merge this branch: | bzr merge lp:~michael.nelson/launchpad/635005-difference-details-2 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Henning Eggers (community) | code | Approve | |
Curtis Hovey (community) | ui | Approve | |
Abel Deuring (community) | code | Approve | |
Review via email: mp+35640@code.launchpad.net |
Commit message
Add extra details of DistroSeriesDif
Description of the change
Overview
========
This branch adds comment rendering to the extra-details template for DistroSeriesDif
https:/
Details
=======
This branch adds and tests the rendering of comments on the distroseriesdif
It then adds JS to enhance this by loading the snippet and adding it inline as an expanded table row.
Note: A large part of the diff below is adding a default view and templates for the lp.services.
To test
=======
bin/test -vv -m test_distroseri
Windmill:
bin/test -vvm test_distroseri
To demo
=======
Run http://
https:/
Michael Nelson (michael.nelson) wrote : | # |
On Thu, Sep 16, 2010 at 1:06 PM, Henning Eggers
<email address hidden> wrote:
> Review: Needs Fixing ui*
> Thank you for that great screencast. I just installed "recordmydesktop", too. ;-)
>
> As you mentioned and we discussed in IRC you should use the same style for comments as we have elsewhere on Launchpad. But feel free to propose to change our comments to contain (smaller) logos/head shots of uses. ;-)
Yep. Also, I've just found lp.services.
refactor a bit to use that.
>
> Also discussed: The items in the list of available diffs should be preceded by a download icon and the list should be indented.
Yes for the icon, but when the actual diffs are displayed (perhaps not
when they need to be requested first). And +1 for the indentation too.
> I am also wondering (not discussed) if this section could not be reworded like this:
>
> Differences from last common version:
>
> * Derived version: 1.15-2ubuntu1de
> * Base version: 1.17-1 (0.5kB)
>
> I think this is clearer and has less noise. The word "package" here was noise, too, because we are already in a table row that is about this package. I am just wondering if the whole line should be the link or just the version number. In the latter case the download icon would end up in the middle of the line, which might not be desirable. Maybe you can play around with that a bit to see what looks best.
Sounds good. I'll hopefully have something tomorrow morning :)
Henning Eggers (henninge) wrote : | # |
The comments section looks good now and the wording for the differences is perfect. Thank you. You fixed the "binary descriptions" sections, too, which I had forgotten to mention. Good job! I guess I was wrong about the idention but this is fine, too. I'd still like the download icon but will not hold the review on this. Let's hear Paul's take on this ... ;-)
Thank you very much again!
Paul, I think I should be in "Launchpad UI Reviewers", shouldn't I?
Michael Nelson (michael.nelson) wrote : | # |
On Fri, Sep 17, 2010 at 11:04 AM, Henning Eggers
<email address hidden> wrote:
> Review: Approve ui*
> The comments section looks good now and the wording for the differences is perfect. Thank you. You fixed the "binary descriptions" sections, too, which I had forgotten to mention. Good job! I guess I was wrong about the idention but this is fine, too. I'd still like the download icon but will not hold the review on this. Let's hear Paul's take on this ... ;-)
Thanks Henning. Just to be clear, I also want the download icon - but
only when there is something to download. The current UI is
representing the state where we *could* generate that PackageDiff if
the user requests it, but I need to add the JS to do that. Once the
diff has been generated I'm all for it being displayed with the icon
(and updating the similar link on PPA packages to do the same).
@Paul: I'm actually updating the lp.services.
some generic templates/views. I'll hopefully have pushed this by the
time you check, so in addition to the UI review, would you mind
glancing over the lp.services.
it's inline with what the code team envisaged. Thanks.
Abel Deuring (adeuring) wrote : | # |
nice work!
Curtis Hovey (sinzui) wrote : | # |
This is excellent. I have no remarks; well done Henning.
Michael Nelson (michael.nelson) wrote : | # |
I had to make the following changes to ensure code's use of comments renders with their own templates, rather than the default ones for IComment:
http://
As well as ensuring the zcml links up the correct template, it also ensures that the code comment classes (CodeReviewDisp
Henning Eggers (henninge) wrote : | # |
The incremental diff looks good to me. ;-) Placing the marker interface in the browser code seems to be common practice.
Preview Diff
1 | === modified file 'lib/canonical/launchpad/interfaces/_schema_circular_imports.py' |
2 | --- lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2010-08-27 11:19:54 +0000 |
3 | +++ lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2010-09-21 11:03:45 +0000 |
4 | @@ -89,6 +89,7 @@ |
5 | IStructuralSubscription, |
6 | IStructuralSubscriptionTarget, |
7 | ) |
8 | +from lp.services.comments.interfaces.conversation import IComment |
9 | from lp.soyuz.enums import ( |
10 | PackagePublishingStatus, |
11 | PackageUploadCustomFormat, |
12 | @@ -321,6 +322,9 @@ |
13 | IBuildFarmJob['status'].vocabulary = BuildStatus |
14 | IBuildFarmJob['buildqueue_record'].schema = IBuildQueue |
15 | |
16 | +# IComment |
17 | +IComment['comment_author'].schema = IPerson |
18 | + |
19 | # IDistribution |
20 | IDistribution['series'].value_type.schema = IDistroSeries |
21 | patch_reference_property( |
22 | |
23 | === modified file 'lib/lp/app/templates/base-layout-macros.pt' |
24 | --- lib/lp/app/templates/base-layout-macros.pt 2010-08-20 13:33:51 +0000 |
25 | +++ lib/lp/app/templates/base-layout-macros.pt 2010-09-21 11:03:45 +0000 |
26 | @@ -183,6 +183,8 @@ |
27 | <script type="text/javascript" |
28 | tal:attributes="src string:${lp_js}/bugs/bugtracker_overlay.js"></script> |
29 | <script type="text/javascript" |
30 | + tal:attributes="src string:${lp_js}/registry/distroseriesdifferences_details.js"></script> |
31 | + <script type="text/javascript" |
32 | tal:attributes="src string:${lp_js}/registry/milestoneoverlay.js"></script> |
33 | <script type="text/javascript" |
34 | tal:attributes="src string:${lp_js}/registry/milestonetable.js"></script> |
35 | |
36 | === modified file 'lib/lp/code/browser/branchmergeproposal.py' |
37 | --- lib/lp/code/browser/branchmergeproposal.py 2010-08-24 10:45:57 +0000 |
38 | +++ lib/lp/code/browser/branchmergeproposal.py 2010-09-21 11:03:45 +0000 |
39 | @@ -547,7 +547,7 @@ |
40 | return diff_text.count('\n') >= config.diff.max_format_lines |
41 | |
42 | |
43 | -class ICodeReviewNewRevisions(Interface): |
44 | +class ICodeReviewNewRevisions(IComment): |
45 | """Marker interface used to register views for CodeReviewNewRevisions.""" |
46 | |
47 | |
48 | @@ -557,7 +557,7 @@ |
49 | Each object instance represents a number of revisions scanned at a |
50 | particular time. |
51 | """ |
52 | - implements(IComment, ICodeReviewNewRevisions) |
53 | + implements(ICodeReviewNewRevisions) |
54 | |
55 | def __init__(self, revisions, date, branch): |
56 | self.revisions = revisions |
57 | @@ -567,6 +567,13 @@ |
58 | # The date attribute is used to sort the comments in the conversation. |
59 | self.date = date |
60 | |
61 | + # Other standard IComment attributes are not used. |
62 | + self.extra_css_class = None |
63 | + self.comment_author = None |
64 | + self.body_text = None |
65 | + self.comment_date = None |
66 | + self.display_attachments = False |
67 | + |
68 | |
69 | class CodeReviewNewRevisionsView(LaunchpadView): |
70 | """The view for rendering the new revisions.""" |
71 | |
72 | === modified file 'lib/lp/code/browser/codereviewcomment.py' |
73 | --- lib/lp/code/browser/codereviewcomment.py 2010-08-24 10:45:57 +0000 |
74 | +++ lib/lp/code/browser/codereviewcomment.py 2010-09-21 11:03:45 +0000 |
75 | @@ -43,6 +43,10 @@ |
76 | from lp.services.propertycache import cachedproperty |
77 | |
78 | |
79 | +class ICodeReviewDisplayComment(IComment, ICodeReviewComment): |
80 | + """Marker interface for displaying code review comments.""" |
81 | + |
82 | + |
83 | class CodeReviewDisplayComment: |
84 | """A code review comment or activity or both. |
85 | |
86 | @@ -51,7 +55,7 @@ |
87 | only code in the model itself. |
88 | """ |
89 | |
90 | - implements(IComment) |
91 | + implements(ICodeReviewDisplayComment) |
92 | |
93 | delegates(ICodeReviewComment, 'comment') |
94 | |
95 | @@ -70,6 +74,40 @@ |
96 | else: |
97 | return '' |
98 | |
99 | + @cachedproperty |
100 | + def comment_author(self): |
101 | + """The author of the comment.""" |
102 | + return self.comment.message.owner |
103 | + |
104 | + @cachedproperty |
105 | + def has_body(self): |
106 | + """Is there body text?""" |
107 | + return bool(self.body_text) |
108 | + |
109 | + @cachedproperty |
110 | + def body_text(self): |
111 | + """Get the body text for the message.""" |
112 | + return self.comment.message_body |
113 | + |
114 | + @cachedproperty |
115 | + def comment_date(self): |
116 | + """The date of the comment.""" |
117 | + return self.comment.message.datecreated |
118 | + |
119 | + @cachedproperty |
120 | + def all_attachments(self): |
121 | + return self.comment.getAttachments() |
122 | + |
123 | + @cachedproperty |
124 | + def display_attachments(self): |
125 | + # Attachments to show. |
126 | + return [DiffAttachment(alias) for alias in self.all_attachments[0]] |
127 | + |
128 | + @cachedproperty |
129 | + def other_attachments(self): |
130 | + # Attachments to not show. |
131 | + return self.all_attachments[1] |
132 | + |
133 | |
134 | class CodeReviewCommentPrimaryContext: |
135 | """The primary context is the comment is that of the source branch.""" |
136 | @@ -132,45 +170,11 @@ |
137 | """The decorated code review comment.""" |
138 | return CodeReviewDisplayComment(self.context) |
139 | |
140 | - @cachedproperty |
141 | - def comment_author(self): |
142 | - """The author of the comment.""" |
143 | - return self.context.message.owner |
144 | - |
145 | - @cachedproperty |
146 | - def has_body(self): |
147 | - """Is there body text?""" |
148 | - return bool(self.body_text) |
149 | - |
150 | - @cachedproperty |
151 | - def body_text(self): |
152 | - """Get the body text for the message.""" |
153 | - return self.context.message_body |
154 | - |
155 | - @cachedproperty |
156 | - def comment_date(self): |
157 | - """The date of the comment.""" |
158 | - return self.context.message.datecreated |
159 | - |
160 | # Should the comment be shown in full? |
161 | full_comment = True |
162 | # Show comment expanders? |
163 | show_expanders = False |
164 | |
165 | - @cachedproperty |
166 | - def all_attachments(self): |
167 | - return self.context.getAttachments() |
168 | - |
169 | - @cachedproperty |
170 | - def display_attachments(self): |
171 | - # Attachments to show. |
172 | - return [DiffAttachment(alias) for alias in self.all_attachments[0]] |
173 | - |
174 | - @cachedproperty |
175 | - def other_attachments(self): |
176 | - # Attachments to not show. |
177 | - return self.all_attachments[1] |
178 | - |
179 | |
180 | class CodeReviewCommentSummary(CodeReviewCommentView): |
181 | """Summary view of a CodeReviewComment""" |
182 | |
183 | === modified file 'lib/lp/code/browser/configure.zcml' |
184 | --- lib/lp/code/browser/configure.zcml 2010-09-20 00:20:42 +0000 |
185 | +++ lib/lp/code/browser/configure.zcml 2010-09-21 11:03:45 +0000 |
186 | @@ -691,6 +691,16 @@ |
187 | name="+index" |
188 | template="../templates/codereviewcomment-index.pt"/> |
189 | <browser:page |
190 | + name="+fragment" |
191 | + template="../templates/codereviewcomment-fragment.pt"/> |
192 | + </browser:pages> |
193 | + <browser:pages |
194 | + facet="branches" |
195 | + for="lp.code.browser.codereviewcomment.ICodeReviewDisplayComment" |
196 | + layer="lp.code.publisher.CodeLayer" |
197 | + class="lp.code.browser.codereviewcomment.CodeReviewCommentView" |
198 | + permission="zope.Public"> |
199 | + <browser:page |
200 | name="+comment-header" |
201 | template="../templates/codereviewcomment-header.pt"/> |
202 | <browser:page |
203 | @@ -699,9 +709,6 @@ |
204 | <browser:page |
205 | name="+comment-footer" |
206 | template="../templates/codereviewcomment-footer.pt"/> |
207 | - <browser:page |
208 | - name="+fragment" |
209 | - template="../templates/codereviewcomment-fragment.pt"/> |
210 | </browser:pages> |
211 | <browser:pages |
212 | facet="branches" |
213 | |
214 | === modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py' |
215 | --- lib/lp/code/browser/tests/test_branchmergeproposal.py 2010-08-22 21:34:16 +0000 |
216 | +++ lib/lp/code/browser/tests/test_branchmergeproposal.py 2010-09-21 11:03:45 +0000 |
217 | @@ -24,6 +24,7 @@ |
218 | from canonical.launchpad.database.message import MessageSet |
219 | from canonical.launchpad.webapp.interfaces import IPrimaryContext |
220 | from canonical.launchpad.webapp.servers import LaunchpadTestRequest |
221 | +from canonical.launchpad.webapp.testing import verifyObject |
222 | from canonical.testing import ( |
223 | DatabaseFunctionalLayer, |
224 | LaunchpadFunctionalLayer, |
225 | @@ -36,8 +37,10 @@ |
226 | BranchMergeProposalMergedView, |
227 | BranchMergeProposalVoteView, |
228 | DecoratedCodeReviewVoteReference, |
229 | + ICodeReviewNewRevisions, |
230 | latest_proposals_for_each_branch, |
231 | ) |
232 | +from lp.code.browser.codereviewcomment import CodeReviewDisplayComment |
233 | from lp.code.enums import ( |
234 | BranchMergeProposalStatus, |
235 | CodeReviewVote, |
236 | @@ -634,6 +637,21 @@ |
237 | [revisions[2], revisions[3]]] |
238 | self.assertRevisionGroups(bmp, expected_groups) |
239 | |
240 | + def test_CodeReviewNewRevisions_implements_ICodeReviewNewRevisions(self): |
241 | + # The browser helper class implements its interface. |
242 | + review_date = datetime(2009, 9, 10, tzinfo=pytz.UTC) |
243 | + revision_date = review_date + timedelta(days=1) |
244 | + bmp = self.factory.makeBranchMergeProposal( |
245 | + date_created=review_date) |
246 | + revision = add_revision_to_branch( |
247 | + self.factory, bmp.source_branch, revision_date) |
248 | + |
249 | + view = create_initialized_view(bmp, '+index') |
250 | + groups = view._getRevisionsSinceReviewStart() |
251 | + new_revisions = groups[0] |
252 | + |
253 | + self.assertTrue(verifyObject(ICodeReviewNewRevisions, new_revisions)) |
254 | + |
255 | def test_include_superseded_comments(self): |
256 | for x, time in zip(range(3), time_counter()): |
257 | if x != 0: |
258 | @@ -767,7 +785,8 @@ |
259 | body='testing', |
260 | attachments=[('test.diff', 'text/plain', attachment_body)]) |
261 | message = MessageSet().fromEmail(msg.as_string()) |
262 | - return bmp.createCommentFromMessage(message, None, None, msg) |
263 | + return CodeReviewDisplayComment( |
264 | + bmp.createCommentFromMessage(message, None, None, msg)) |
265 | |
266 | def test_nonascii_in_attachment_renders(self): |
267 | # The view should render without errors. |
268 | @@ -783,7 +802,7 @@ |
269 | # Need to commit in order to read the diff out of the librarian. |
270 | transaction.commit() |
271 | view = create_initialized_view(comment, '+comment-body') |
272 | - [diff_attachment] = view.display_attachments |
273 | + [diff_attachment] = view.comment.display_attachments |
274 | self.assertEqual(u'\u2615', diff_attachment.diff_text) |
275 | |
276 | |
277 | |
278 | === modified file 'lib/lp/code/browser/tests/test_codereviewcomment.py' |
279 | --- lib/lp/code/browser/tests/test_codereviewcomment.py 2010-08-20 20:31:18 +0000 |
280 | +++ lib/lp/code/browser/tests/test_codereviewcomment.py 2010-09-21 11:03:45 +0000 |
281 | @@ -3,35 +3,52 @@ |
282 | |
283 | """Unit tests for CodeReviewComments.""" |
284 | |
285 | +from __future__ import with_statement |
286 | + |
287 | __metaclass__ = type |
288 | |
289 | import unittest |
290 | |
291 | from canonical.launchpad.webapp.interfaces import IPrimaryContext |
292 | +from canonical.launchpad.webapp.testing import verifyObject |
293 | from canonical.testing import DatabaseFunctionalLayer |
294 | +from lp.code.browser.codereviewcomment import ( |
295 | + CodeReviewDisplayComment, |
296 | + ICodeReviewDisplayComment, |
297 | + ) |
298 | from lp.testing import ( |
299 | - login_person, |
300 | + person_logged_in, |
301 | TestCaseWithFactory, |
302 | ) |
303 | |
304 | |
305 | -class TestCodeReviewCommentPrimaryContext(TestCaseWithFactory): |
306 | - # Tests the adaptation of a code review comment into a primary context. |
307 | +class TestCodeReviewComments(TestCaseWithFactory): |
308 | |
309 | layer = DatabaseFunctionalLayer |
310 | |
311 | def testPrimaryContext(self): |
312 | + # Tests the adaptation of a code review comment into a primary |
313 | + # context. |
314 | # We need a person to make a comment. |
315 | - commenter = self.factory.makePerson() |
316 | - login_person(commenter) |
317 | - # The primary context of a code review comment is the same as the |
318 | - # primary context for the branch merge proposal that the comment is |
319 | - # for. |
320 | - comment = self.factory.makeCodeReviewComment() |
321 | + with person_logged_in(self.factory.makePerson()): |
322 | + # The primary context of a code review comment is the same |
323 | + # as the primary context for the branch merge proposal that |
324 | + # the comment is for. |
325 | + comment = self.factory.makeCodeReviewComment() |
326 | + |
327 | self.assertEqual( |
328 | IPrimaryContext(comment).context, |
329 | IPrimaryContext(comment.branch_merge_proposal).context) |
330 | |
331 | + def test_display_comment_provides_icodereviewdisplaycomment(self): |
332 | + # The CodeReviewDisplayComment class provides IComment. |
333 | + with person_logged_in(self.factory.makePerson()): |
334 | + comment = self.factory.makeCodeReviewComment() |
335 | + |
336 | + display_comment = CodeReviewDisplayComment(comment) |
337 | + |
338 | + verifyObject(ICodeReviewDisplayComment, display_comment) |
339 | + |
340 | |
341 | def test_suite(): |
342 | return unittest.TestLoader().loadTestsFromName(__name__) |
343 | |
344 | === modified file 'lib/lp/code/templates/codereviewcomment-body.pt' |
345 | --- lib/lp/code/templates/codereviewcomment-body.pt 2010-04-16 04:20:43 +0000 |
346 | +++ lib/lp/code/templates/codereviewcomment-body.pt 2010-09-21 11:03:45 +0000 |
347 | @@ -3,9 +3,9 @@ |
348 | xmlns:metal="http://xml.zope.org/namespaces/metal" |
349 | omit-tag=""> |
350 | |
351 | - <tal:message replace="structure view/body_text/fmt:obfuscate-email/fmt:nice_pre" /> |
352 | + <tal:message replace="structure view/comment/body_text/fmt:obfuscate-email/fmt:nice_pre" /> |
353 | |
354 | - <tal:good-attachments repeat="attachment view/display_attachments"> |
355 | + <tal:good-attachments repeat="attachment view/comment/display_attachments"> |
356 | <div class="boardComment attachment"> |
357 | <div class="boardCommentDetails filename"><a tal:content="attachment/filename" tal:attributes="href attachment/getURL"/></div> |
358 | <div class="boardCommentBody attachmentBody" tal:content="structure attachment/diff_text/fmt:diff"/> |
359 | |
360 | === modified file 'lib/lp/code/templates/codereviewcomment-header.pt' |
361 | --- lib/lp/code/templates/codereviewcomment-header.pt 2010-02-18 16:40:09 +0000 |
362 | +++ lib/lp/code/templates/codereviewcomment-header.pt 2010-09-21 11:03:45 +0000 |
363 | @@ -3,9 +3,9 @@ |
364 | xmlns:metal="http://xml.zope.org/namespaces/metal" |
365 | omit-tag=""> |
366 | |
367 | - <tal:author replace="structure view/comment_author/fmt:link:mainsite"/> |
368 | - <tal:has-body condition="view/has_body">wrote</tal:has-body> |
369 | - <tal:date replace="view/comment_date/fmt:displaydate" /> |
370 | + <tal:author replace="structure context/comment_author/fmt:link:mainsite"/> |
371 | + <tal:has-body condition="context/has_body">wrote</tal:has-body> |
372 | + <tal:date replace="context/comment_date/fmt:displaydate" /> |
373 | <span tal:condition="context/from_superseded" class="sprite warning-icon" |
374 | style="float: right">Posted in <a |
375 | tal:attributes="href context/branch_merge_proposal/fmt:url">a |
376 | |
377 | === modified file 'lib/lp/registry/browser/configure.zcml' |
378 | --- lib/lp/registry/browser/configure.zcml 2010-09-13 10:04:20 +0000 |
379 | +++ lib/lp/registry/browser/configure.zcml 2010-09-21 11:03:45 +0000 |
380 | @@ -151,7 +151,7 @@ |
381 | permission="zope.Public"/> |
382 | <browser:url |
383 | for="lp.registry.interfaces.distroseriesdifference.IDistroSeriesDifference" |
384 | - path_expression="string:+difference/${difference/source_package_name}" |
385 | + path_expression="string:+difference/${source_package_name/name}" |
386 | rootsite="mainsite" |
387 | attribute_to_parent="derived_series"/> |
388 | <browser:page |
389 | @@ -160,6 +160,9 @@ |
390 | class="lp.registry.browser.distroseriesdifference.DistroSeriesDifferenceView" |
391 | template="../templates/distroseriesdifference-listing-extra.pt" |
392 | permission="zope.Public"/> |
393 | + <browser:defaultView |
394 | + for="lp.registry.interfaces.distroseriesdifference.IDistroSeriesDifference" |
395 | + name="+listing-distroseries-extra"/> |
396 | <browser:menus |
397 | classes=" |
398 | DistroSeriesFacets |
399 | |
400 | === modified file 'lib/lp/registry/browser/distroseriesdifference.py' |
401 | --- lib/lp/registry/browser/distroseriesdifference.py 2010-09-13 15:09:48 +0000 |
402 | +++ lib/lp/registry/browser/distroseriesdifference.py 2010-09-21 11:03:45 +0000 |
403 | @@ -8,14 +8,22 @@ |
404 | 'DistroSeriesDifferenceView', |
405 | ] |
406 | |
407 | +from zope.interface import implements |
408 | + |
409 | from canonical.launchpad.webapp.publisher import LaunchpadView |
410 | +from lp.services.comments.interfaces.conversation import ( |
411 | + IComment, |
412 | + IConversation, |
413 | + ) |
414 | |
415 | |
416 | class DistroSeriesDifferenceView(LaunchpadView): |
417 | |
418 | + implements(IConversation) |
419 | + |
420 | @property |
421 | - def summary(self): |
422 | - """Return the summary of the related source package.""" |
423 | + def binary_summaries(self): |
424 | + """Return the summary of the related binary packages.""" |
425 | source_pub = None |
426 | if self.context.source_pub is not None: |
427 | source_pub = self.context.source_pub |
428 | @@ -23,7 +31,33 @@ |
429 | source_pub = self.context.parent_source_pub |
430 | |
431 | if source_pub is not None: |
432 | - return source_pub.meta_sourcepackage.summary |
433 | - else: |
434 | - return None |
435 | - |
436 | + summary = source_pub.meta_sourcepackage.summary |
437 | + if summary: |
438 | + return summary.split('\n') |
439 | + |
440 | + return None |
441 | + |
442 | + @property |
443 | + def comments(self): |
444 | + """See `IConversation`.""" |
445 | + # Could use a generator here? |
446 | + return [ |
447 | + DistroSeriesDifferenceDisplayComment(comment) for |
448 | + comment in self.context.getComments()] |
449 | + |
450 | + |
451 | +class DistroSeriesDifferenceDisplayComment: |
452 | + """Used simply to provide `IComment` for rendering.""" |
453 | + implements(IComment) |
454 | + |
455 | + has_body = True |
456 | + has_footer = False |
457 | + display_attachments = False |
458 | + extra_css_class = '' |
459 | + |
460 | + def __init__(self, comment): |
461 | + """Setup the attributes required by `IComment`.""" |
462 | + self.message_body = comment.comment |
463 | + self.comment_author = comment.message.owner |
464 | + self.comment_date = comment.message.datecreated |
465 | + self.body_text = comment.comment |
466 | |
467 | === modified file 'lib/lp/registry/browser/tests/test_distroseriesdifference_views.py' |
468 | --- lib/lp/registry/browser/tests/test_distroseriesdifference_views.py 2010-09-14 13:37:17 +0000 |
469 | +++ lib/lp/registry/browser/tests/test_distroseriesdifference_views.py 2010-09-21 11:03:45 +0000 |
470 | @@ -10,12 +10,20 @@ |
471 | from BeautifulSoup import BeautifulSoup |
472 | from zope.component import getUtility |
473 | |
474 | +from canonical.launchpad.webapp.testing import verifyObject |
475 | from canonical.testing import ( |
476 | DatabaseFunctionalLayer, |
477 | LaunchpadFunctionalLayer, |
478 | ) |
479 | +from lp.registry.browser.distroseriesdifference import ( |
480 | + DistroSeriesDifferenceDisplayComment, |
481 | + ) |
482 | from lp.registry.enum import DistroSeriesDifferenceType |
483 | from lp.registry.interfaces.distroseriesdifference import IDistroSeriesDifferenceSource |
484 | +from lp.services.comments.interfaces.conversation import ( |
485 | + IComment, |
486 | + IConversation, |
487 | + ) |
488 | from lp.soyuz.enums import PackagePublishingStatus |
489 | from lp.soyuz.tests.test_publishing import SoyuzTestPublisher |
490 | from lp.testing import ( |
491 | @@ -30,10 +38,28 @@ |
492 | |
493 | layer = DatabaseFunctionalLayer |
494 | |
495 | + def test_provides_conversation(self): |
496 | + # The DSDView provides a conversation implementation. |
497 | + ds_diff = self.factory.makeDistroSeriesDifference() |
498 | + |
499 | + view = create_initialized_view(ds_diff, '+listing-distroseries-extra') |
500 | + self.assertTrue(verifyObject(IConversation, view)) |
501 | + |
502 | + def test_comment_for_display_provides_icomment(self): |
503 | + # The DSDDisplayComment browser object provides IComment. |
504 | + ds_diff = self.factory.makeDistroSeriesDifference() |
505 | + owner = ds_diff.derived_series.owner |
506 | + with person_logged_in(owner): |
507 | + comment = ds_diff.addComment(owner, "I'm working on this.") |
508 | + comment_for_display = DistroSeriesDifferenceDisplayComment(comment) |
509 | + |
510 | + self.assertTrue(verifyObject(IComment, comment_for_display)) |
511 | + |
512 | def addSummaryToDifference(self, distro_series_difference): |
513 | """Helper that adds binaries with summary info to the source pubs.""" |
514 | distro_series = distro_series_difference.derived_series |
515 | - source_package_name_str = distro_series_difference.source_package_name.name |
516 | + source_package_name_str = ( |
517 | + distro_series_difference.source_package_name.name) |
518 | stp = SoyuzTestPublisher() |
519 | |
520 | if distro_series_difference.difference_type == ( |
521 | @@ -52,7 +78,7 @@ |
522 | distro_series, source_package_name_str) |
523 | return ds_diff |
524 | |
525 | - def test_summary_for_source_pub(self): |
526 | + def test_binary_summaries_for_source_pub(self): |
527 | # For packages unique to the derived series (or different |
528 | # versions) the summary is based on the derived source pub. |
529 | ds_diff = self.factory.makeDistroSeriesDifference() |
530 | @@ -60,11 +86,13 @@ |
531 | |
532 | view = create_initialized_view(ds_diff, '+listing-distroseries-extra') |
533 | |
534 | - self.assertIsNot(None, view.summary) |
535 | - self.assertEqual( |
536 | - ds_diff.source_pub.meta_sourcepackage.summary, view.summary) |
537 | + self.assertIsNot(None, view.binary_summaries) |
538 | + self.assertEqual([ |
539 | + u'flubber-bin: summary for flubber-bin', |
540 | + u'flubber-lib: summary for flubber-lib', |
541 | + ], view.binary_summaries) |
542 | |
543 | - def test_summary_for_missing_difference(self): |
544 | + def test_binary_summaries_for_missing_difference(self): |
545 | # For packages only in the parent series, the summary is based |
546 | # on the parent publication. |
547 | ds_diff = self.factory.makeDistroSeriesDifference( |
548 | @@ -74,12 +102,13 @@ |
549 | |
550 | view = create_initialized_view(ds_diff, '+listing-distroseries-extra') |
551 | |
552 | - self.assertIsNot(None, view.summary) |
553 | - self.assertEqual( |
554 | - ds_diff.parent_source_pub.meta_sourcepackage.summary, |
555 | - view.summary) |
556 | + self.assertIsNot(None, view.binary_summaries) |
557 | + self.assertEqual([ |
558 | + u'flubber-bin: summary for flubber-bin', |
559 | + u'flubber-lib: summary for flubber-lib', |
560 | + ], view.binary_summaries) |
561 | |
562 | - def test_summary_no_pubs(self): |
563 | + def test_binary_summaries_no_pubs(self): |
564 | # If the difference has been resolved by removing packages then |
565 | # there will not be a summary. |
566 | ds_diff = self.factory.makeDistroSeriesDifference( |
567 | @@ -93,7 +122,7 @@ |
568 | |
569 | self.assertIs(None, ds_diff.parent_source_pub) |
570 | self.assertIs(None, ds_diff.source_pub) |
571 | - self.assertIs(None, view.summary) |
572 | + self.assertIs(None, view.binary_summaries) |
573 | |
574 | |
575 | class DistroSeriesDifferenceTemplateTestCase(TestCaseWithFactory): |
576 | @@ -103,7 +132,7 @@ |
577 | def number_of_request_diff_texts(self, html): |
578 | """Check that the html doesn't include the request diff text.""" |
579 | soup = BeautifulSoup(html) |
580 | - return len(soup.findAll('dd', 'request-derived-diff')) |
581 | + return len(soup.findAll('li', 'request-derived-diff')) |
582 | |
583 | def contains_one_link_to_diff(self, html, package_diff): |
584 | """Return whether the html contains a link to the diff content.""" |
585 | @@ -170,3 +199,19 @@ |
586 | |
587 | view = create_initialized_view(ds_diff, '+listing-distroseries-extra') |
588 | self.assertEqual(1, self.number_of_request_diff_texts(view())) |
589 | + |
590 | + def test_comments_rendered(self): |
591 | + # If there are comments on the difference, they are rendered. |
592 | + ds_diff = self.factory.makeDistroSeriesDifference() |
593 | + owner = ds_diff.derived_series.owner |
594 | + with person_logged_in(owner): |
595 | + ds_diff.addComment(owner, "I'm working on this.") |
596 | + ds_diff.addComment(owner, "Here's another comment.") |
597 | + |
598 | + view = create_initialized_view(ds_diff, '+listing-distroseries-extra') |
599 | + soup = BeautifulSoup(view()) |
600 | + |
601 | + self.assertEqual( |
602 | + 1, len(soup.findAll('pre', text="I'm working on this."))) |
603 | + self.assertEqual( |
604 | + 1, len(soup.findAll('pre', text="Here's another comment."))) |
605 | |
606 | === modified file 'lib/lp/registry/browser/tests/test_series_views.py' |
607 | --- lib/lp/registry/browser/tests/test_series_views.py 2010-09-08 07:53:06 +0000 |
608 | +++ lib/lp/registry/browser/tests/test_series_views.py 2010-09-21 11:03:45 +0000 |
609 | @@ -181,6 +181,25 @@ |
610 | self.assertIn("Latest comment", unicode(rows[0])) |
611 | self.assertNotIn("Earlier comment", unicode(rows[0])) |
612 | |
613 | + def test_diff_row_links_to_extra_details(self): |
614 | + # The source package name links to the difference details. |
615 | + derived_series = self.makeDerivedSeries( |
616 | + parent_name='lucid', derived_name='derilucid') |
617 | + difference = self.factory.makeDistroSeriesDifference( |
618 | + derived_series=derived_series) |
619 | + |
620 | + self.setDerivedSeriesUIFeatureFlag() |
621 | + view = create_initialized_view( |
622 | + derived_series, '+localpackagediffs') |
623 | + soup = BeautifulSoup(view()) |
624 | + diff_table = soup.find('table', {'class': 'listing'}) |
625 | + row = diff_table.tbody.findAll('tr')[0] |
626 | + |
627 | + href = canonical_url(difference).replace('http://launchpad.dev', '') |
628 | + links = row.findAll('a', href=href) |
629 | + self.assertEqual(1, len(links)) |
630 | + self.assertEqual(difference.source_package_name.name, links[0].string) |
631 | + |
632 | |
633 | class TestMilestoneBatchNavigatorAttribute(TestCaseWithFactory): |
634 | """Test the series.milestone_batch_navigator attribute.""" |
635 | |
636 | === added file 'lib/lp/registry/javascript/distroseriesdifferences_details.js' |
637 | --- lib/lp/registry/javascript/distroseriesdifferences_details.js 1970-01-01 00:00:00 +0000 |
638 | +++ lib/lp/registry/javascript/distroseriesdifferences_details.js 2010-09-21 11:03:45 +0000 |
639 | @@ -0,0 +1,86 @@ |
640 | +/* Copyright 2010 Canonical Ltd. This software is licensed under the |
641 | + * GNU Affero General Public License version 3 (see the file LICENSE). |
642 | + * |
643 | + * Enhancements for the distroseries differences page. |
644 | + * |
645 | + * @module registry |
646 | + * @submodule distroseriesdifferences_details |
647 | + * @requires io-base, lp.soyuz.base |
648 | + */ |
649 | +YUI.add('lp.registry.distroseriesdifferences_details', function(Y) { |
650 | + |
651 | +var namespace = Y.namespace('lp.registry.distroseriesdifferences_details'); |
652 | + |
653 | +/* |
654 | + * Setup the expandable rows for each difference. |
655 | + * |
656 | + * @method setup_expandable_rows |
657 | + */ |
658 | +namespace.setup_expandable_rows = function() { |
659 | + var start_update = function(uri, container) { |
660 | + |
661 | + var in_progress_message = Y.lp.soyuz.base.makeInProgressNode( |
662 | + 'Fetching difference details ...') |
663 | + container.insert(in_progress_message, 'replace'); |
664 | + |
665 | + var config = { |
666 | + on: { |
667 | + 'success': function(transaction_id, response, args) { |
668 | + args.container.set( |
669 | + 'innerHTML', response.responseText); |
670 | + // Change to insert(,'replace) |
671 | + }, |
672 | + 'failure': function(transaction_id, response, args){ |
673 | + var retry_handler = function(e) { |
674 | + e.preventDefault(); |
675 | + start_update(args.uri, args.container); |
676 | + }; |
677 | + var failure_message = Y.lp.soyuz.base.makeFailureNode( |
678 | + 'Failed to fetch difference details.', |
679 | + retry_handler); |
680 | + args.container.insert(failure_message, 'replace'); |
681 | + |
682 | + var anim = Y.lazr.anim.red_flash({ |
683 | + node: args.container |
684 | + }); |
685 | + anim.run(); |
686 | + } |
687 | + }, |
688 | + arguments: { |
689 | + 'container': container, |
690 | + 'uri': uri |
691 | + } |
692 | + }; |
693 | + Y.io(uri, config); |
694 | + |
695 | + }; |
696 | + |
697 | + var expander_handler = function(e) { |
698 | + e.preventDefault(); |
699 | + var toggle = e.currentTarget; |
700 | + var row = toggle.ancestor('tr'); |
701 | + toggle.toggleClass('treeCollapsed').toggleClass('treeExpanded'); |
702 | + |
703 | + // Only insert if there isn't already a container row there. |
704 | + next_row = row.next(); |
705 | + if (next_row == null || !next_row.hasClass('diff-extra')) { |
706 | + details_row = Y.Node.create( |
707 | + '<table><tr class="diff-extra unseen"><td colspan="5"></td></tr></table>').one('tr'); |
708 | + row.insert(details_row, 'after'); |
709 | + var uri = toggle.get('href'); |
710 | + start_update(uri, details_row.one('td')); |
711 | + } else { |
712 | + details_row = next_row |
713 | + } |
714 | + |
715 | + details_row.toggleClass('unseen'); |
716 | + |
717 | + }; |
718 | + Y.all('table.listing a.toggle-extra').each(function(toggle){ |
719 | + toggle.addClass('treeCollapsed').addClass('sprite'); |
720 | + toggle.on("click", expander_handler); |
721 | + }) |
722 | + |
723 | +}; |
724 | + |
725 | +}, "0.1", {"requires": ["io-base", "lp.soyuz.base"]}); |
726 | |
727 | === modified file 'lib/lp/registry/templates/distroseries-localdifferences.pt' |
728 | --- lib/lp/registry/templates/distroseries-localdifferences.pt 2010-09-08 09:18:11 +0000 |
729 | +++ lib/lp/registry/templates/distroseries-localdifferences.pt 2010-09-21 11:03:45 +0000 |
730 | @@ -45,8 +45,8 @@ |
731 | <tr tal:define="parent_source_pub difference/parent_source_pub; |
732 | source_pub difference/source_pub; |
733 | signer source_pub/sourcepackagerelease/uploader/fmt:link|nothing;"> |
734 | - <td><span |
735 | - tal:replace="parent_source_pub/source_package_name">Foo</span> |
736 | + <td><a tal:attributes="href difference/fmt:url" class="toggle-extra" |
737 | + tal:content="parent_source_pub/source_package_name">Foo</a> |
738 | </td> |
739 | <td><a tal:attributes="href parent_source_pub/sourcepackagerelease/fmt:url"> |
740 | <tal:replace |
741 | @@ -79,6 +79,13 @@ |
742 | </tbody> |
743 | </table> |
744 | </div> |
745 | +<script type="text/javascript"> |
746 | +LPS.use('lp.registry.distroseriesdifferences_details', function(Y) { |
747 | + diff_module = Y.lp.registry.distroseriesdifferences_details |
748 | + |
749 | + Y.on('domready', diff_module.setup_expandable_rows); |
750 | +}); |
751 | +</script> |
752 | |
753 | </div> |
754 | |
755 | |
756 | === modified file 'lib/lp/registry/templates/distroseriesdifference-listing-extra.pt' |
757 | --- lib/lp/registry/templates/distroseriesdifference-listing-extra.pt 2010-09-14 13:37:17 +0000 |
758 | +++ lib/lp/registry/templates/distroseriesdifference-listing-extra.pt 2010-09-21 11:03:45 +0000 |
759 | @@ -4,31 +4,43 @@ |
760 | xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
761 | i18n:domain="launchpad"> |
762 | <dl> |
763 | - <dt>Description:</dt> |
764 | - <dd><tal:description replace="view/summary" /></dd> |
765 | + <dt>Binary descriptions:</dt> |
766 | + <dd><ul> |
767 | + <li tal:repeat="summary view/binary_summaries"> |
768 | + <tal:description replace="summary" /></li> |
769 | + </ul></dd> |
770 | <dt>Last common version:</dt> |
771 | <dd>Not implemented.</dd> |
772 | - <dt>Package differences:</dt> |
773 | - <tal:source-diff-option condition="context/source_pub"> |
774 | - <dd tal:condition="context/package_diff" |
775 | - tal:content="structure context/package_diff/fmt:link"> |
776 | - <a>link to a diff</a></dd> |
777 | - <dd tal:condition="not: context/package_diff" class="request-derived-diff"> |
778 | - Base version to derived <span |
779 | + <dt>Differences from last common version:</dt> |
780 | + <dd> |
781 | + <ul> |
782 | + <tal:source-diff-option condition="context/source_pub"> |
783 | + <li tal:condition="context/package_diff" |
784 | + tal:content="structure context/package_diff/fmt:link"> |
785 | + <a>link to a diff</a></li> |
786 | + <li tal:condition="not: context/package_diff" class="request-derived-diff"> |
787 | + <span tal:replace="context/derived_series/displayname"> |
788 | + Derilucid</span> version: <span |
789 | tal:replace="context/source_version">1.2.3</span> |
790 | - </dd> |
791 | - </tal:source-diff-option> |
792 | + </li> |
793 | + </tal:source-diff-option> |
794 | |
795 | - <tal:parent-diff-option condition="context/parent_source_pub"> |
796 | - <dd tal:condition="context/parent_package_diff" |
797 | - tal:content="structure context/parent_package_diff/fmt:link"> |
798 | - <a>link to a diff</a></dd> |
799 | - <dd tal:condition="not: context/parent_package_diff" class="request-derived-diff"> |
800 | - Base version to parent <span |
801 | - tal:replace="context/parent_source_version">1.2.3</span> |
802 | + <tal:parent-diff-option condition="context/parent_source_pub"> |
803 | + <li tal:condition="context/parent_package_diff" |
804 | + tal:content="structure context/parent_package_diff/fmt:link"> |
805 | + <a>link to a diff</a></li> |
806 | + <li tal:condition="not: context/parent_package_diff" class="request-derived-diff"> |
807 | + <span |
808 | + tal:replace="context/derived_series/parent_series/displayname"> |
809 | + Lucid</span> version: <span |
810 | + tal:replace="context/parent_source_version">1.2.3</span> |
811 | + </li> |
812 | + </tal:parent-diff-option> |
813 | + </ul> |
814 | </dd> |
815 | - </tal:parent-diff-option> |
816 | </dl> |
817 | + |
818 | <h2>Comments:</h2> |
819 | + <tal:conversation replace="structure view/@@+render"/> |
820 | |
821 | </tal:root> |
822 | |
823 | === added file 'lib/lp/registry/windmill/tests/test_distroseriesdifference_expander.py' |
824 | --- lib/lp/registry/windmill/tests/test_distroseriesdifference_expander.py 1970-01-01 00:00:00 +0000 |
825 | +++ lib/lp/registry/windmill/tests/test_distroseriesdifference_expander.py 2010-09-21 11:03:45 +0000 |
826 | @@ -0,0 +1,42 @@ |
827 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
828 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
829 | + |
830 | +import transaction |
831 | + |
832 | +from canonical.launchpad.webapp.publisher import canonical_url |
833 | +from canonical.launchpad.windmill.testing import constants |
834 | +from lp.registry.windmill.testing import RegistryWindmillLayer |
835 | +from lp.services.features.model import FeatureFlag, getFeatureStore |
836 | +from lp.testing import WindmillTestCase |
837 | + |
838 | + |
839 | +class TestDistroSeriesDifferenceExtraJS(WindmillTestCase): |
840 | + """Each listed source package can be expanded for extra information.""" |
841 | + |
842 | + layer = RegistryWindmillLayer |
843 | + |
844 | + def setUp(self): |
845 | + """Enable the feature and populate with data.""" |
846 | + super(TestDistroSeriesDifferenceExtraJS, self).setUp() |
847 | + # First just ensure that the feature is enabled. |
848 | + getFeatureStore().add(FeatureFlag( |
849 | + scope=u'default', flag=u'soyuz.derived-series-ui.enabled', |
850 | + value=u'on', priority=1)) |
851 | + |
852 | + # Setup the difference record. |
853 | + self.diff = self.factory.makeDistroSeriesDifference( |
854 | + source_package_name_str="foo", versions=dict( |
855 | + derived='1.15-2ubuntu1derilucid2', parent='1.17-1')) |
856 | + transaction.commit() |
857 | + |
858 | + self.package_diffs_url = ( |
859 | + canonical_url(self.diff.derived_series) + '/+localpackagediffs') |
860 | + |
861 | + def test_diff_extra_details_available(self): |
862 | + """A successful request for the extra info updates the display.""" |
863 | + self.client.open(url=self.package_diffs_url) |
864 | + self.client.waits.forPageLoad(timeout=constants.PAGE_LOAD) |
865 | + self.client.click(link=u'foo') |
866 | + self.client.waits.forElement( |
867 | + classname=u'diff-extra', timeout=constants.FOR_ELEMENT) |
868 | + |
869 | |
870 | === modified file 'lib/lp/services/comments/browser/configure.zcml' |
871 | --- lib/lp/services/comments/browser/configure.zcml 2009-07-17 02:25:09 +0000 |
872 | +++ lib/lp/services/comments/browser/configure.zcml 2010-09-21 11:03:45 +0000 |
873 | @@ -15,10 +15,18 @@ |
874 | permission="zope.Public" |
875 | template="../templates/conversation.pt"/> |
876 | |
877 | - <browser:page |
878 | - name="+render" |
879 | + <browser:pages |
880 | for="lp.services.comments.interfaces.conversation.IComment" |
881 | - permission="zope.Public" |
882 | - template="../templates/comment.pt"/> |
883 | + permission="zope.Public"> |
884 | + <browser:page |
885 | + name="+render" |
886 | + template="../templates/comment.pt"/> |
887 | + <browser:page |
888 | + name="+comment-header" |
889 | + template="../templates/comment-header.pt"/> |
890 | + <browser:page |
891 | + name="+comment-body" |
892 | + template="../templates/comment-body.pt"/> |
893 | + </browser:pages> |
894 | |
895 | </configure> |
896 | |
897 | === modified file 'lib/lp/services/comments/interfaces/conversation.py' |
898 | --- lib/lp/services/comments/interfaces/conversation.py 2010-08-20 20:31:18 +0000 |
899 | +++ lib/lp/services/comments/interfaces/conversation.py 2010-09-21 11:03:45 +0000 |
900 | @@ -17,6 +17,8 @@ |
901 | from zope.interface import Interface |
902 | from zope.schema import ( |
903 | Bool, |
904 | + Datetime, |
905 | + Text, |
906 | TextLine, |
907 | ) |
908 | |
909 | @@ -37,6 +39,22 @@ |
910 | description=_("Does the comment have a footer?"), |
911 | readonly=True) |
912 | |
913 | + body_text = Text( |
914 | + description=_("The body text of the comment."), |
915 | + readonly=True) |
916 | + |
917 | + comment_author = Reference( |
918 | + # Really IPerson. |
919 | + Interface, title=_("The author of the comment."), |
920 | + readonly=True) |
921 | + |
922 | + comment_date = Datetime( |
923 | + title=_('Comment date.'), readonly=True) |
924 | + |
925 | + display_attachments = Bool( |
926 | + description=_("Should attachments be displayed for this comment."), |
927 | + readonly=True) |
928 | + |
929 | |
930 | class IConversation(Interface): |
931 | """A conversation has a number of comments.""" |
932 | |
933 | === added file 'lib/lp/services/comments/templates/comment-body.pt' |
934 | --- lib/lp/services/comments/templates/comment-body.pt 1970-01-01 00:00:00 +0000 |
935 | +++ lib/lp/services/comments/templates/comment-body.pt 2010-09-21 11:03:45 +0000 |
936 | @@ -0,0 +1,8 @@ |
937 | +<tal:root |
938 | + xmlns:tal="http://xml.zope.org/namespaces/tal" |
939 | + xmlns:metal="http://xml.zope.org/namespaces/metal" |
940 | + omit-tag=""> |
941 | + |
942 | + <tal:message replace="structure context/body_text/fmt:obfuscate-email/fmt:nice_pre" /> |
943 | + |
944 | +</tal:root> |
945 | |
946 | === added file 'lib/lp/services/comments/templates/comment-header.pt' |
947 | --- lib/lp/services/comments/templates/comment-header.pt 1970-01-01 00:00:00 +0000 |
948 | +++ lib/lp/services/comments/templates/comment-header.pt 2010-09-21 11:03:45 +0000 |
949 | @@ -0,0 +1,9 @@ |
950 | +<tal:root |
951 | + xmlns:tal="http://xml.zope.org/namespaces/tal" |
952 | + xmlns:metal="http://xml.zope.org/namespaces/metal" |
953 | + omit-tag=""> |
954 | + |
955 | + <tal:author replace="structure context/comment_author/fmt:link:mainsite"/> |
956 | + <tal:has-body condition="context/has_body">wrote</tal:has-body> |
957 | + <tal:date replace="context/comment_date/fmt:displaydate" /> |
958 | +</tal:root> |
Thank you for that great screencast. I just installed "recordmydesktop", too. ;-)
As you mentioned and we discussed in IRC you should use the same style for comments as we have elsewhere on Launchpad. But feel free to propose to change our comments to contain (smaller) logos/head shots of uses. ;-)
Also discussed: The items in the list of available diffs should be preceded by a download icon and the list should be indented. I am also wondering (not discussed) if this section could not be reworded like this:
Differences from last common version:
* Derived version: 1.15-2ubuntu1de rilucid2 (1.2kB)
* Base version: 1.17-1 (0.5kB)
I think this is clearer and has less noise. The word "package" here was noise, too, because we are already in a table row that is about this package. I am just wondering if the whole line should be the link or just the version number. In the latter case the download icon would end up in the middle of the line, which might not be desirable. Maybe you can play around with that a bit to see what looks best.
I am not approving this yet because I'd like to see the outcome of this and also the inclusion of the standard LP comments first.