Merge lp:~wgrant/launchpad/misc-fixes into lp:launchpad

Proposed by William Grant
Status: Merged
Merged at revision: 17242
Proposed branch: lp:~wgrant/launchpad/misc-fixes
Merge into: lp:launchpad
Diff against target: 523 lines (+136/-85)
15 files modified
lib/lp/app/javascript/sorttable/sorttable.js (+2/-2)
lib/lp/bugs/browser/bugtask.py (+35/-41)
lib/lp/bugs/browser/configure.zcml (+2/-14)
lib/lp/bugs/browser/tests/test_bugtask.py (+39/-1)
lib/lp/bugs/model/bug.py (+10/-3)
lib/lp/bugs/templates/bugtasks-index.pt (+0/-7)
lib/lp/bugs/tests/test_bug.py (+26/-1)
lib/lp/code/emailtemplates/branch-merge-proposal-created.txt (+1/-2)
lib/lp/code/emailtemplates/branch-merge-proposal-updated.txt (+0/-1)
lib/lp/code/emailtemplates/review-requested.txt (+1/-2)
lib/lp/code/mail/tests/test_branchmergeproposal.py (+1/-4)
lib/lp/registry/stories/product/xx-product-index.txt (+12/-0)
lib/lp/registry/stories/teammembership/xx-member-renewed-membership.txt (+2/-2)
lib/lp/registry/templates/product-index.pt (+1/-1)
lib/lp/registry/templates/teammembership-self-renewal.pt (+4/-4)
To merge this branch: bzr merge lp:~wgrant/launchpad/misc-fixes
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+241850@code.launchpad.net

Commit message

Drop duplicate CVE link, fix bugtask sort order with derived distros, avoid redirecting to bugs in inactive products, fix +expiringmembership grammar, drop duplicate MP email link, fix +bugs title, flip sort arrows, don't show irrelevant license info.

Description of the change

Just a wide selection of trivial UI bugs.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== renamed file 'lib/canonical/launchpad/images/order-descending.png' => 'lib/canonical/launchpad/images/order-ascending.png'
2=== renamed file 'lib/canonical/launchpad/images/order-ascending.png' => 'lib/canonical/launchpad/images/order-descending.png'
3=== modified file 'lib/lp/app/javascript/sorttable/sorttable.js'
4--- lib/lp/app/javascript/sorttable/sorttable.js 2012-04-23 14:01:43 +0000
5+++ lib/lp/app/javascript/sorttable/sorttable.js 2014-11-14 22:32:06 +0000
6@@ -135,7 +135,7 @@
7 headrow.removeChild(document.getElementById('sorttable_sortfwdind'));
8 sortrevind = document.createElement('span');
9 sortrevind.id = "sorttable_sortrevind";
10- sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;';
11+ sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25BE;';
12 headrow.appendChild(sortrevind);
13 return;
14 }
15@@ -169,7 +169,7 @@
16 headrow.className += ' sorttable_sorted';
17 sortfwdind = document.createElement('span');
18 sortfwdind.id = "sorttable_sortfwdind";
19- sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
20+ sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25B4;';
21 headrow.appendChild(sortfwdind);
22
23 // build an array to sort. This is a Schwartzian transform thing,
24
25=== modified file 'lib/lp/bugs/browser/bugtask.py'
26--- lib/lp/bugs/browser/bugtask.py 2014-10-22 18:38:16 +0000
27+++ lib/lp/bugs/browser/bugtask.py 2014-11-14 22:32:06 +0000
28@@ -1,4 +1,4 @@
29-# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
30+# Copyright 2009-2014 Canonical Ltd. This software is licensed under the
31 # GNU Affero General Public License version 3 (see the file LICENSE).
32
33 """IBugTask-related browser views."""
34@@ -26,7 +26,6 @@
35 'BugTaskPrivacyAdapter',
36 'BugTaskRemoveQuestionView',
37 'BugTaskSearchListingView',
38- 'BugTaskSetNavigation',
39 'BugTasksNominationsView',
40 'BugTasksTableView',
41 'BugTaskTableRowView',
42@@ -263,7 +262,6 @@
43 from lp.services.webapp import (
44 canonical_url,
45 enabled_with_permission,
46- GetitemNavigation,
47 LaunchpadView,
48 Link,
49 Navigation,
50@@ -613,11 +611,6 @@
51 redirection('references', '..')
52
53
54-class BugTaskSetNavigation(GetitemNavigation):
55- """Navigation for the `IbugTaskSet`."""
56- usedfor = IBugTaskSet
57-
58-
59 class BugTaskContextMenu(BugContextMenu):
60 """Context menu of actions that can be performed upon an `IBugTask`."""
61 usedfor = IBugTask
62@@ -2412,29 +2405,17 @@
63 @property
64 def links(self):
65 bug_target = self.context.context
66- if IDistribution.providedBy(bug_target):
67- return (
68- 'cve',
69- )
70- elif IDistroSeries.providedBy(bug_target):
71- return (
72- 'cve',
73+ if IDistroSeries.providedBy(bug_target):
74+ return (
75 'nominations',
76 )
77- elif IProduct.providedBy(bug_target):
78- return (
79- 'cve',
80- )
81- elif IProductSeries.providedBy(bug_target):
82+ if IProductSeries.providedBy(bug_target):
83 return (
84 'nominations',
85 )
86 else:
87 return ()
88
89- def cve(self):
90- return Link('+cve', 'CVE reports', icon='cve')
91-
92 @enabled_with_permission('launchpad.Edit')
93 def bugsupervisor(self):
94 return Link('+bugsupervisor', 'Change bug supervisor', icon='edit')
95@@ -2590,7 +2571,7 @@
96
97 @property
98 def page_title(self):
99- return "Bugs : %s" % self.context.displayname
100+ return "Bugs for %s" % self.context.displayname
101
102 label = page_title
103
104@@ -3348,9 +3329,34 @@
105 getUtility(IBugTaskSet).searchBugIds(search_params))
106
107
108-def _by_targetname(bugtask):
109- """Normalize the bugtask.targetname, for sorting."""
110- return re.sub(r"\W", "", bugtask.bugtargetdisplayname)
111+def bugtask_sort_key(bugtask):
112+ """Return a sort key for displaying a set of tasks for a single bug.
113+
114+ Designed to make sense when bugtargetdisplayname is shown.
115+ """
116+ if IDistribution.providedBy(bugtask.target):
117+ return (
118+ None, bugtask.target.displayname, None, None, None)
119+ elif IDistroSeries.providedBy(bugtask.target):
120+ return (
121+ None, bugtask.target.distribution.displayname,
122+ bugtask.target.name, None, None)
123+ elif IDistributionSourcePackage.providedBy(bugtask.target):
124+ return (
125+ bugtask.target.sourcepackagename.name,
126+ bugtask.target.distribution.displayname, None, None, None)
127+ elif ISourcePackage.providedBy(bugtask.target):
128+ return (
129+ bugtask.target.sourcepackagename.name,
130+ bugtask.target.distribution.displayname,
131+ bugtask.target.distroseries.name, None, None)
132+ elif IProduct.providedBy(bugtask.target):
133+ return (None, None, None, bugtask.target.displayname, None)
134+ elif IProductSeries.providedBy(bugtask.target):
135+ return (
136+ None, None, None, bugtask.target.product.displayname,
137+ bugtask.target.name)
138+ raise AssertionError("No sort key for %r" % bugtask.target)
139
140
141 class BugTasksNominationsView(LaunchpadView):
142@@ -3626,19 +3632,7 @@
143 included in the returned results.
144 """
145 bug = self.context
146- bugtasks = self.bugtasks
147-
148- upstream_tasks = [
149- bugtask for bugtask in bugtasks
150- if bugtask.product or bugtask.productseries]
151-
152- distro_tasks = [
153- bugtask for bugtask in bugtasks
154- if bugtask.distribution or bugtask.distroseries]
155-
156- upstream_tasks.sort(key=_by_targetname)
157- distro_tasks.sort(key=_by_targetname)
158- all_bugtasks = upstream_tasks + distro_tasks
159+ all_bugtasks = list(sorted(self.bugtasks, key=bugtask_sort_key))
160
161 # Cache whether the bug was converted to a question, since
162 # bug.getQuestionCreatedFromBug issues a db query each time it
163@@ -3684,7 +3678,7 @@
164 name='+bugtasks-and-nominations-table-row'))
165
166 conjoined_master = bugtask.getConjoinedMaster(
167- bugtasks, bugtasks_by_package)
168+ all_bugtasks, bugtasks_by_package)
169 view = self._getTableRowView(
170 bugtask, is_converted_to_question,
171 conjoined_master is not None)
172
173=== modified file 'lib/lp/bugs/browser/configure.zcml'
174--- lib/lp/bugs/browser/configure.zcml 2014-02-19 00:35:25 +0000
175+++ lib/lp/bugs/browser/configure.zcml 2014-11-14 22:32:06 +0000
176@@ -1,4 +1,4 @@
177-<!-- Copyright 2010-2012 Canonical Ltd. This software is licensed under the
178+<!-- Copyright 2010-2014 Canonical Ltd. This software is licensed under the
179 GNU Affero General Public License version 3 (see the file LICENSE).
180 -->
181
182@@ -468,9 +468,7 @@
183 rootsite="bugs"/>
184 <browser:navigation
185 module="lp.bugs.browser.bugtask"
186- classes="
187- BugTaskNavigation
188- BugTaskSetNavigation"/>
189+ classes="BugTaskNavigation"/>
190 <browser:page
191 for="lp.bugs.interfaces.bug.IBug"
192 class="lp.bugs.browser.bug.BugSubscriptionPortletView"
193@@ -545,16 +543,6 @@
194 class="lp.bugs.browser.bug.BugMarkAsAffectingUserView"
195 permission="launchpad.AnyPerson"
196 template="../templates/bug-mark-as-affecting-user.pt"/>
197- <browser:defaultView
198- for="lp.bugs.interfaces.bugtask.IBugTaskSet"
199- name="+index"/>
200- <browser:pages
201- for="lp.bugs.interfaces.bugtask.IBugTaskSet"
202- permission="zope.Public">
203- <browser:page
204- name="+index"
205- template="../templates/bugtasks-index.pt"/>
206- </browser:pages>
207 <browser:page
208 name="+addcomment"
209 for="lp.bugs.interfaces.bugtask.IBugTask"
210
211=== modified file 'lib/lp/bugs/browser/tests/test_bugtask.py'
212--- lib/lp/bugs/browser/tests/test_bugtask.py 2013-10-24 06:20:06 +0000
213+++ lib/lp/bugs/browser/tests/test_bugtask.py 2014-11-14 22:32:06 +0000
214@@ -1,4 +1,4 @@
215-# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
216+# Copyright 2009-2014 Canonical Ltd. This software is licensed under the
217 # GNU Affero General Public License version 3 (see the file LICENSE).
218
219 __metaclass__ = type
220@@ -835,6 +835,44 @@
221 foo_bugtasks_and_nominations_view.getBugTaskAndNominationViews())
222 self.assertEqual([], task_and_nomination_views)
223
224+ def test_bugtask_sorting(self):
225+ # Product tasks come first, sorted by product then series.
226+ # Distro tasks follow, sorted by package, distribution, then
227+ # series.
228+ foo = self.factory.makeProduct(displayname='Foo')
229+ self.factory.makeProductSeries(product=foo, name='2.0')
230+ self.factory.makeProductSeries(product=foo, name='1.0')
231+ bar = self.factory.makeProduct(displayname='Bar')
232+ self.factory.makeProductSeries(product=bar, name='0.0')
233+
234+ barix = self.factory.makeDistribution(displayname='Barix')
235+ self.factory.makeDistroSeries(distribution=barix, name='beta')
236+ self.factory.makeDistroSeries(distribution=barix, name='alpha')
237+ fooix = self.factory.makeDistribution(displayname='Fooix')
238+ self.factory.makeDistroSeries(distribution=fooix, name='beta')
239+
240+ foo_spn = self.factory.makeSourcePackageName('foo')
241+ bar_spn = self.factory.makeSourcePackageName('bar')
242+
243+ expected_targets = [
244+ bar, bar.getSeries('0.0'),
245+ foo, foo.getSeries('1.0'), foo.getSeries('2.0'),
246+ barix.getSourcePackage(bar_spn),
247+ barix.getSeries('beta').getSourcePackage(bar_spn),
248+ fooix.getSourcePackage(bar_spn),
249+ fooix.getSeries('beta').getSourcePackage(bar_spn),
250+ barix.getSourcePackage(foo_spn),
251+ barix.getSeries('alpha').getSourcePackage(foo_spn),
252+ ]
253+
254+ bug = self.factory.makeBug(target=expected_targets[0])
255+ for target in expected_targets[1:]:
256+ self.factory.makeBugTask(bug=bug, target=target)
257+ view = create_initialized_view(bug, "+bugtasks-and-nominations-table")
258+ subviews = view.getBugTaskAndNominationViews()
259+ self.assertEqual(
260+ expected_targets, [v.context.target for v in subviews])
261+
262 def test_bugtarget_parent_shown_for_orphaned_series_tasks(self):
263 # Test that a row is shown for the parent of a series task, even
264 # if the parent doesn't actually have a task.
265
266=== modified file 'lib/lp/bugs/model/bug.py'
267--- lib/lp/bugs/model/bug.py 2014-04-29 00:44:32 +0000
268+++ lib/lp/bugs/model/bug.py 2014-11-14 22:32:06 +0000
269@@ -1,4 +1,4 @@
270-# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
271+# Copyright 2009-2014 Canonical Ltd. This software is licensed under the
272 # GNU Affero General Public License version 3 (see the file LICENSE).
273
274 """Launchpad bug-related database table classes."""
275@@ -44,6 +44,7 @@
276 )
277 from storm.expr import (
278 And,
279+ Coalesce,
280 Desc,
281 In,
282 Join,
283@@ -650,8 +651,14 @@
284 @property
285 def default_bugtask(self):
286 """See `IBug`."""
287- return Store.of(self).find(
288- BugTask, bug=self).order_by(BugTask.id).first()
289+ from lp.registry.model.product import Product
290+ return Store.of(self).using(
291+ BugTask,
292+ LeftJoin(Product, Product.id == BugTask.productID)
293+ ).find(
294+ BugTask, bug=self
295+ ).order_by(
296+ Desc(Coalesce(Product.active, True)), BugTask.id).first()
297
298 @property
299 def is_complete(self):
300
301=== removed file 'lib/lp/bugs/templates/bugtasks-index.pt'
302--- lib/lp/bugs/templates/bugtasks-index.pt 2009-07-17 17:59:07 +0000
303+++ lib/lp/bugs/templates/bugtasks-index.pt 1970-01-01 00:00:00 +0000
304@@ -1,7 +0,0 @@
305-<html
306- xmlns:tal="http://xml.zope.org/namespaces/tal"
307- tal:replace="python:request.response.redirect('..')">
308- <body>
309- <a href=".">Here</a>
310- </body>
311-</html>
312
313=== modified file 'lib/lp/bugs/tests/test_bug.py'
314--- lib/lp/bugs/tests/test_bug.py 2013-10-22 04:09:23 +0000
315+++ lib/lp/bugs/tests/test_bug.py 2014-11-14 22:32:06 +0000
316@@ -1,4 +1,4 @@
317-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
318+# Copyright 2009-2014 Canonical Ltd. This software is licensed under the
319 # GNU Affero General Public License version 3 (see the file LICENSE).
320
321 """Tests for lp.bugs.model.Bug."""
322@@ -24,6 +24,7 @@
323 UserCannotEditBugTaskMilestone,
324 )
325 from lp.testing import (
326+ admin_logged_in,
327 person_logged_in,
328 StormStatementRecorder,
329 TestCaseWithFactory,
330@@ -31,6 +32,30 @@
331 from lp.testing.layers import DatabaseFunctionalLayer
332
333
334+class TestBug(TestCaseWithFactory):
335+ layer = DatabaseFunctionalLayer
336+
337+ def test_default_bugtask(self):
338+ product = self.factory.makeProduct()
339+ bug = self.factory.makeBug(target=product)
340+ first_task = bug.default_bugtask
341+ other_task = self.factory.makeBugTask(
342+ bug=bug, target=self.factory.makeProduct())
343+ self.assertEqual(first_task, bug.default_bugtask)
344+ # default_bugtask avoids an inactive product if possible.
345+ with admin_logged_in():
346+ first_task.target.active = False
347+ self.assertEqual(other_task, bug.default_bugtask)
348+ # But it'll use the first inactive one if it has to.
349+ with admin_logged_in():
350+ other_task.target.active = False
351+ self.assertEqual(first_task, bug.default_bugtask)
352+ # An active distro task wins over an inactive product.
353+ distro_task = self.factory.makeBugTask(
354+ bug=bug, target=self.factory.makeDistribution())
355+ self.assertEqual(distro_task, bug.default_bugtask)
356+
357+
358 class TestBugSubscriptionMethods(TestCaseWithFactory):
359 layer = DatabaseFunctionalLayer
360
361
362=== modified file 'lib/lp/code/emailtemplates/branch-merge-proposal-created.txt'
363--- lib/lp/code/emailtemplates/branch-merge-proposal-created.txt 2012-09-18 21:49:22 +0000
364+++ lib/lp/code/emailtemplates/branch-merge-proposal-created.txt 2014-11-14 22:32:06 +0000
365@@ -4,5 +4,4 @@
366 For more details, see:
367 %(proposal_url)s%(gap)s%(comment)s
368 --
369-%(diff_cutoff_warning)s%(proposal_url)s
370-%(reason)s%(edit_subscription)s
371+%(diff_cutoff_warning)s%(reason)s%(edit_subscription)s
372
373=== modified file 'lib/lp/code/emailtemplates/branch-merge-proposal-updated.txt'
374--- lib/lp/code/emailtemplates/branch-merge-proposal-updated.txt 2011-12-18 22:31:46 +0000
375+++ lib/lp/code/emailtemplates/branch-merge-proposal-updated.txt 2014-11-14 22:32:06 +0000
376@@ -5,5 +5,4 @@
377 For more details, see:
378 %(proposal_url)s
379 --
380-%(proposal_url)s
381 %(reason)s%(edit_subscription)s
382
383=== modified file 'lib/lp/code/emailtemplates/review-requested.txt'
384--- lib/lp/code/emailtemplates/review-requested.txt 2011-12-18 22:31:46 +0000
385+++ lib/lp/code/emailtemplates/review-requested.txt 2014-11-14 22:32:06 +0000
386@@ -6,5 +6,4 @@
387 %(comment)s
388
389 --
390-%(diff_cutoff_warning)s%(proposal_url)s
391-%(reason)s%(edit_subscription)s
392+%(diff_cutoff_warning)s%(reason)s%(edit_subscription)s
393
394=== modified file 'lib/lp/code/mail/tests/test_branchmergeproposal.py'
395--- lib/lp/code/mail/tests/test_branchmergeproposal.py 2013-06-20 05:50:00 +0000
396+++ lib/lp/code/mail/tests/test_branchmergeproposal.py 2014-11-14 22:32:06 +0000
397@@ -1,4 +1,4 @@
398-# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
399+# Copyright 2009-2014 Canonical Ltd. This software is licensed under the
400 # GNU Affero General Public License version 3 (see the file LICENSE).
401
402 """Tests for BranchMergeProposal mailings"""
403@@ -114,7 +114,6 @@
404 For more details, see:
405 %(bmp)s
406 --\x20
407- %(bmp)s
408 %(reason)s
409 """) % {
410 'source': bmp.source_branch.bzr_identity,
411@@ -516,7 +515,6 @@
412 For more details, see:
413 %(bmp)s
414 --\x20
415- %(bmp)s
416 You are the owner of lp://dev/~bob/super-product/fix-foo-for-bar.
417 """) % {
418 'source': bmp.source_branch.bzr_identity,
419@@ -644,7 +642,6 @@
420 This branch is awesome.
421
422 --\x20
423- %(bmp)s
424 You are requested to review the proposed merge of %(source)s"""
425 """ into %(target)s.
426 """ % {
427
428=== modified file 'lib/lp/registry/stories/product/xx-product-index.txt'
429--- lib/lp/registry/stories/product/xx-product-index.txt 2014-09-08 08:07:06 +0000
430+++ lib/lp/registry/stories/product/xx-product-index.txt 2014-11-14 22:32:06 +0000
431@@ -122,6 +122,7 @@
432 >>> firefox = Product.selectOneBy(name="firefox")
433 >>> ignored = login_person(firefox.owner)
434 >>> firefox.licenses = [License.OTHER_PROPRIETARY]
435+ >>> firefox.license_info = u"Internal project."
436 >>> flush_database_updates()
437 >>> transaction.commit()
438 >>> logout()
439@@ -145,6 +146,12 @@
440 >>> user_browser.open('http://launchpad.dev/firefox')
441 >>> user_browser.contents
442 '<...This project&rsquo;s licence is proprietary...
443+ >>> print extract_text(
444+ ... find_tag_by_id(user_browser.contents, 'licences'))
445+ Licences:
446+ Other/Proprietary (Internal project.)
447+ Commercial subscription expires ...
448+
449
450 A non-owner does not see that a commercial subscription is due.
451
452@@ -169,6 +176,11 @@
453 >>> user_browser.open('http://launchpad.dev/firefox')
454 >>> print find_tag_by_id(owner_browser.contents, 'license-status')
455 None
456+ >>> print extract_text(
457+ ... find_tag_by_id(user_browser.contents, 'licences'))
458+ Licences:
459+ GNU GPL v2
460+ Commercial subscription expires ...
461
462
463 Commercial Subscription Expiration
464
465=== modified file 'lib/lp/registry/stories/teammembership/xx-member-renewed-membership.txt'
466--- lib/lp/registry/stories/teammembership/xx-member-renewed-membership.txt 2012-08-02 14:18:36 +0000
467+++ lib/lp/registry/stories/teammembership/xx-member-renewed-membership.txt 2014-11-14 22:32:06 +0000
468@@ -107,7 +107,7 @@
469 >>> print extract_text(find_tag_by_id(browser.contents, 'maincontent'))
470 Renew membership of Karl Tilbury in Mirror Administrators
471 ...
472- This membership is going to expire in ... from now; if you want to
473+ This membership is going to expire ... from now. If you want to
474 remain a member of Mirror Administrators, you must renew it.
475 or Cancel
476
477@@ -162,7 +162,7 @@
478 >>> print extract_text(find_tag_by_id(browser.contents, 'maincontent'))
479 Renew membership of Landscape Developers in Mirror Administrators
480 ...
481- This membership is going to expire in ... from now; if you want this team
482+ This membership is going to expire ... from now. If you want this team
483 to remain a member of Mirror Administrators, you must renew it.
484 or Cancel
485
486
487=== modified file 'lib/lp/registry/templates/product-index.pt'
488--- lib/lp/registry/templates/product-index.pt 2013-01-25 06:08:10 +0000
489+++ lib/lp/registry/templates/product-index.pt 2014-11-14 22:32:06 +0000
490@@ -138,7 +138,7 @@
491 </tal:licenses>
492 <tal:none condition="not:context/licenses">None specified</tal:none>
493 <div class="scrolled-box"
494- condition="view/show_license_info">
495+ tal:condition="view/show_license_info">
496 (<tal:license_info replace="context/license_info" />)
497 </div>
498 </dd>
499
500=== modified file 'lib/lp/registry/templates/teammembership-self-renewal.pt'
501--- lib/lp/registry/templates/teammembership-self-renewal.pt 2011-12-08 22:41:00 +0000
502+++ lib/lp/registry/templates/teammembership-self-renewal.pt 2014-11-14 22:32:06 +0000
503@@ -13,16 +13,16 @@
504 <div tal:condition="context/canBeRenewedByMember">
505 <div metal:use-macro="context/@@launchpad_form/form">
506 <p metal:fill-slot="extra_info">
507- This membership is going to expire in
508+ This membership is going to expire
509 <span tal:replace="view/time_before_expiration/fmt:approximateduration"
510- /> from now;
511+ /> from now.
512 <tal:is-team condition="context/person/is_team">
513- if you want this team to remain a member of
514+ If you want this team to remain a member of
515 <span tal:replace="structure context/team/fmt:link" />,
516 you must renew it.
517 </tal:is-team>
518 <tal:not-team condition="not: context/person/is_team">
519- if you want to remain a member of
520+ If you want to remain a member of
521 <span tal:replace="structure context/team/fmt:link" />,
522 you must renew it.
523 </tal:not-team>