Merge lp:~wallyworld/launchpad/sharing-details-delete-966641 into lp:launchpad
- sharing-details-delete-966641
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Curtis Hovey |
Approved revision: | no longer in the source branch. |
Merged at revision: | 15067 |
Proposed branch: | lp:~wallyworld/launchpad/sharing-details-delete-966641 |
Merge into: | lp:launchpad |
Diff against target: |
1612 lines (+949/-138) 32 files modified
lib/lp/app/javascript/activator/tests/test_activator.js (+1/-1) lib/lp/app/javascript/autocomplete/tests/test_autocomplete.js (+1/-1) lib/lp/app/javascript/choiceedit/tests/test_choiceedit.js (+1/-1) lib/lp/app/javascript/confirmationoverlay/tests/test_confirmationoverlay.js (+1/-1) lib/lp/app/javascript/formoverlay/tests/test_formoverlay.js (+1/-1) lib/lp/app/javascript/formwidgets/tests/test_resizing_textarea.js (+1/-1) lib/lp/app/javascript/inlineedit/tests/test_inline_edit.js (+1/-1) lib/lp/app/javascript/overlay/tests/test_overlay.js (+1/-1) lib/lp/app/javascript/picker/tests/test_picker.js (+1/-1) lib/lp/app/javascript/picker/tests/test_picker_patcher.js (+1/-1) lib/lp/app/javascript/subscribers/tests/test_subscribers_list.js (+1/-1) lib/lp/app/javascript/testing/tests/test_mockio.js (+1/-1) lib/lp/app/javascript/tests/test_ajax_batch_navigator.js (+1/-1) lib/lp/app/javascript/tests/test_ajax_log.js (+1/-1) lib/lp/app/javascript/tests/test_beta_notification.js (+1/-1) lib/lp/bugs/javascript/bugtask_index.js (+2/-1) lib/lp/registry/browser/pillar.py (+29/-8) lib/lp/registry/browser/tests/test_pillar_sharing.py (+69/-3) lib/lp/registry/javascript/sharing/pillarsharingview.js (+2/-2) lib/lp/registry/javascript/sharing/sharingdetails.js (+90/-36) lib/lp/registry/javascript/sharing/sharingdetailsview.js (+202/-0) lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js (+1/-1) lib/lp/registry/javascript/sharing/tests/test_shareelisting_navigator.js (+1/-1) lib/lp/registry/javascript/sharing/tests/test_shareepicker.js (+1/-1) lib/lp/registry/javascript/sharing/tests/test_shareetable.js (+1/-1) lib/lp/registry/javascript/sharing/tests/test_sharingdetails.html (+9/-7) lib/lp/registry/javascript/sharing/tests/test_sharingdetails.js (+149/-46) lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.html (+66/-0) lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js (+305/-0) lib/lp/registry/javascript/tests/test_team.js (+1/-1) lib/lp/registry/templates/pillar-sharing-details.pt (+5/-14) standard_test_template.js (+1/-1) |
To merge this branch: | bzr merge lp:~wallyworld/launchpad/sharing-details-delete-966641 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Curtis Hovey (community) | code | Approve | |
Review via email: mp+100551@code.launchpad.net |
Commit message
Add initial ui support for revoking an access grant for a bug or branch.
Description of the change
== Implementation ==
This is the first branch in a series to add the ability to revoke an artifact access grant from the sharing details page. It implements the user interface and make the server calls to do the work but the server side isn't implemented yet. That will be done next.
The PillarPersonSha
A new yui class was implemented - SharingDetailsView. The implementation is similar to that used for the sharing information page. A view/controller class grabs data from the json request cache, instantiates and renders the required widgets, wires up listeners to the various links/buttons, makes any server side calls required, renders the results. The existing SharingDetailsTable is used as a widget to render the main portion of the view.
== Tests ==
A fair bit of clean up was done to the existing test_sharingdetails yui test to make it align with the current test templates and consistent with the other sharing yui tests. New tests were added to test the delete button etc.
A new yui test test_sharingdet
On the server side of things, the PillarSharingDe
bin/test -vvct test_pillar_sharing -t test_sharingdet
== Lint ==
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
Ian Booth (wallyworld) wrote : | # |
Thanks for the review.
On 04/04/12 01:58, Curtis Hovey wrote:
> Review: Approve code
>
> I see the SharingDetailsT
>
The initialiser doesn't need the setters - because bugs and branches are
declared as attributes, if there are present in the config passed to the
initialiser, the attributes are set automatically. So the code that was
removed as totally redundant.
The view/controller grabs the bugs and branches from the data model
(json cache) and uses these to initialise the widget.
> Line 355 repeats the common mistake of creating a sprite without allocating space for it. Elements with sprites must contain content, add a nbsp;
> <span class="sprite bug-{{bug_
>
Right. Missed fixing that one. Sorry.
> Line 529 has bogus markup "<br><br>" never use two <br />, because more than one means your markup and css is broken. Most browser strip all but the first one when rendering sibling blocks because they know css is the correct way to handle the situation. the <br /> must state it is empty as well. I can see the style attr is used with a class. This markup is just broken. I am certain it came from somewhere else in Lp.
>
Will fix.
> This is a small semantic issue I share with Julian, "should" implies we are uncertain about how the code we wrote operates. "Should" on lines 729 and 999 adds a Heisenberg/
> "Could not locate the "
The text in question came from the test template that Rick did. I'll fix
the text here and in the template.
Preview Diff
1 | === modified file 'lib/lp/app/javascript/activator/tests/test_activator.js' |
2 | --- lib/lp/app/javascript/activator/tests/test_activator.js 2012-02-03 19:12:02 +0000 |
3 | +++ lib/lp/app/javascript/activator/tests/test_activator.js 2012-04-04 05:02:23 +0000 |
4 | @@ -69,7 +69,7 @@ |
5 | |
6 | test_library_exists: function () { |
7 | Y.Assert.isObject(Y.lazr.activator, |
8 | - "We should be able to locate the lazr.activator module"); |
9 | + "Could not locate the lazr.activator module"); |
10 | }, |
11 | |
12 | test_correct_animation_node: function() { |
13 | |
14 | === modified file 'lib/lp/app/javascript/autocomplete/tests/test_autocomplete.js' |
15 | --- lib/lp/app/javascript/autocomplete/tests/test_autocomplete.js 2012-02-03 17:57:36 +0000 |
16 | +++ lib/lp/app/javascript/autocomplete/tests/test_autocomplete.js 2012-04-04 05:02:23 +0000 |
17 | @@ -49,7 +49,7 @@ |
18 | |
19 | test_library_exists: function () { |
20 | Y.Assert.isObject(Y.lazr.AutoComplete, |
21 | - "We should be able to locate the lazr.autocomplete module"); |
22 | + "Could not locate the lazr.autocomplete module"); |
23 | }, |
24 | |
25 | test_widget_starts_hidden: function() { |
26 | |
27 | === modified file 'lib/lp/app/javascript/choiceedit/tests/test_choiceedit.js' |
28 | --- lib/lp/app/javascript/choiceedit/tests/test_choiceedit.js 2012-02-17 01:47:49 +0000 |
29 | +++ lib/lp/app/javascript/choiceedit/tests/test_choiceedit.js 2012-04-04 05:02:23 +0000 |
30 | @@ -64,7 +64,7 @@ |
31 | |
32 | test_library_exists: function () { |
33 | Y.Assert.isObject(Y.ChoiceSource, |
34 | - "We should be able to locate the lazr.choiceedit " + |
35 | + "Could not locate the lazr.choiceedit " + |
36 | "module"); |
37 | }, |
38 | |
39 | |
40 | === modified file 'lib/lp/app/javascript/confirmationoverlay/tests/test_confirmationoverlay.js' |
41 | --- lib/lp/app/javascript/confirmationoverlay/tests/test_confirmationoverlay.js 2012-02-03 20:37:06 +0000 |
42 | +++ lib/lp/app/javascript/confirmationoverlay/tests/test_confirmationoverlay.js 2012-04-04 05:02:23 +0000 |
43 | @@ -25,7 +25,7 @@ |
44 | |
45 | test_library_exists: function () { |
46 | Y.Assert.isObject(Y.lp.app.confirmationoverlay, |
47 | - "We should be able to locate the lp.app.confirmationoverlay module"); |
48 | + "Could not locate the lp.app.confirmationoverlay module"); |
49 | }, |
50 | |
51 | test_button_set: function() { |
52 | |
53 | === modified file 'lib/lp/app/javascript/formoverlay/tests/test_formoverlay.js' |
54 | --- lib/lp/app/javascript/formoverlay/tests/test_formoverlay.js 2012-02-06 13:30:53 +0000 |
55 | +++ lib/lp/app/javascript/formoverlay/tests/test_formoverlay.js 2012-04-04 05:02:23 +0000 |
56 | @@ -62,7 +62,7 @@ |
57 | |
58 | test_library_exists: function () { |
59 | Y.Assert.isObject(Y.lazr.FormOverlay, |
60 | - "We should be able to locate the lp.lazr.FormOverlay module"); |
61 | + "Could not locate the lp.lazr.FormOverlay module"); |
62 | }, |
63 | |
64 | test_form_overlay_can_be_instantiated: function() { |
65 | |
66 | === modified file 'lib/lp/app/javascript/formwidgets/tests/test_resizing_textarea.js' |
67 | --- lib/lp/app/javascript/formwidgets/tests/test_resizing_textarea.js 2012-02-06 13:32:56 +0000 |
68 | +++ lib/lp/app/javascript/formwidgets/tests/test_resizing_textarea.js 2012-04-04 05:02:23 +0000 |
69 | @@ -54,7 +54,7 @@ |
70 | |
71 | test_library_exists: function () { |
72 | Y.Assert.isObject(Y.lp.app.formwidgets.ResizingTextarea, |
73 | - "We should be able to locate the " + |
74 | + "Could not locate the " + |
75 | "lp.app.formwidgets.ResizingTextarea module"); |
76 | }, |
77 | |
78 | |
79 | === modified file 'lib/lp/app/javascript/inlineedit/tests/test_inline_edit.js' |
80 | --- lib/lp/app/javascript/inlineedit/tests/test_inline_edit.js 2012-03-01 20:35:55 +0000 |
81 | +++ lib/lp/app/javascript/inlineedit/tests/test_inline_edit.js 2012-04-04 05:02:23 +0000 |
82 | @@ -106,7 +106,7 @@ |
83 | }, |
84 | test_library_exists: function () { |
85 | Y.Assert.isObject(Y.InlineEditor, |
86 | - "We should be able to locate the lp.${LIBRARY} module"); |
87 | + "Could not locate the lp.${LIBRARY} module"); |
88 | }, |
89 | |
90 | test_input_value_set_during_sync: function() { |
91 | |
92 | === modified file 'lib/lp/app/javascript/overlay/tests/test_overlay.js' |
93 | --- lib/lp/app/javascript/overlay/tests/test_overlay.js 2012-02-06 18:01:41 +0000 |
94 | +++ lib/lp/app/javascript/overlay/tests/test_overlay.js 2012-04-04 05:02:23 +0000 |
95 | @@ -48,7 +48,7 @@ |
96 | |
97 | test_library_exists: function () { |
98 | Y.Assert.isObject(Y.lazr.PrettyOverlay, |
99 | - "We should be able to locate the lazr.PrettyOverlay module"); |
100 | + "Could not locate the lazr.PrettyOverlay module"); |
101 | }, |
102 | |
103 | hitEscape: function() { |
104 | |
105 | === modified file 'lib/lp/app/javascript/picker/tests/test_picker.js' |
106 | --- lib/lp/app/javascript/picker/tests/test_picker.js 2012-02-06 18:40:00 +0000 |
107 | +++ lib/lp/app/javascript/picker/tests/test_picker.js 2012-04-04 05:02:23 +0000 |
108 | @@ -44,7 +44,7 @@ |
109 | |
110 | test_library_exists: function () { |
111 | Y.Assert.isObject(Y.lazr.picker, |
112 | - "We should be able to locate the lazr.picker module"); |
113 | + "Could not locate the lazr.picker module"); |
114 | }, |
115 | |
116 | test_picker_can_be_instantiated: function() { |
117 | |
118 | === modified file 'lib/lp/app/javascript/picker/tests/test_picker_patcher.js' |
119 | --- lib/lp/app/javascript/picker/tests/test_picker_patcher.js 2012-02-07 15:56:53 +0000 |
120 | +++ lib/lp/app/javascript/picker/tests/test_picker_patcher.js 2012-04-04 05:02:23 +0000 |
121 | @@ -66,7 +66,7 @@ |
122 | |
123 | test_library_exists: function () { |
124 | Y.Assert.isObject(Y.lp.app.picker, |
125 | - "We should be able to locate the lp.app.picker module"); |
126 | + "Could not locate the lp.app.picker module"); |
127 | }, |
128 | |
129 | create_picker: function(validate_callback, extra_config) { |
130 | |
131 | === modified file 'lib/lp/app/javascript/subscribers/tests/test_subscribers_list.js' |
132 | --- lib/lp/app/javascript/subscribers/tests/test_subscribers_list.js 2012-02-07 19:48:00 +0000 |
133 | +++ lib/lp/app/javascript/subscribers/tests/test_subscribers_list.js 2012-04-04 05:02:23 +0000 |
134 | @@ -103,7 +103,7 @@ |
135 | |
136 | test_library_exists: function () { |
137 | Y.Assert.isObject(Y.lp.app.subscribers.subscribers_list, |
138 | - "We should be able to locate the " + |
139 | + "Could not locate the " + |
140 | "lp.app.subscribers.subscribers_list module"); |
141 | }, |
142 | test_no_container_error: function() { |
143 | |
144 | === modified file 'lib/lp/app/javascript/testing/tests/test_mockio.js' |
145 | --- lib/lp/app/javascript/testing/tests/test_mockio.js 2012-02-10 15:58:36 +0000 |
146 | +++ lib/lp/app/javascript/testing/tests/test_mockio.js 2012-04-04 05:02:23 +0000 |
147 | @@ -45,7 +45,7 @@ |
148 | |
149 | test_library_exists: function () { |
150 | Y.Assert.isObject(Y.lp.testing.mockio, |
151 | - "We should be able to locate the lp.testing.mockio module"); |
152 | + "Could not locate the lp.testing.mockio module"); |
153 | }, |
154 | |
155 | test_respond_success: function() { |
156 | |
157 | === modified file 'lib/lp/app/javascript/tests/test_ajax_batch_navigator.js' |
158 | --- lib/lp/app/javascript/tests/test_ajax_batch_navigator.js 2012-02-07 20:11:18 +0000 |
159 | +++ lib/lp/app/javascript/tests/test_ajax_batch_navigator.js 2012-04-04 05:02:23 +0000 |
160 | @@ -101,7 +101,7 @@ |
161 | |
162 | test_library_exists: function () { |
163 | Y.Assert.isObject(Y.lp.app.batchnavigator, |
164 | - "We should be able to locate the lp.app.batchnavigator"); |
165 | + "Could not locate the lp.app.batchnavigator"); |
166 | }, |
167 | |
168 | test_navigator_construction: function() { |
169 | |
170 | === modified file 'lib/lp/app/javascript/tests/test_ajax_log.js' |
171 | --- lib/lp/app/javascript/tests/test_ajax_log.js 2012-02-15 12:45:13 +0000 |
172 | +++ lib/lp/app/javascript/tests/test_ajax_log.js 2012-04-04 05:02:23 +0000 |
173 | @@ -10,7 +10,7 @@ |
174 | |
175 | test_library_exists: function () { |
176 | Y.Assert.isObject(Y.lp.ajax_log, |
177 | - "We should be able to locate the lp.ajax_log module"); |
178 | + "Could not locate the lp.ajax_log module"); |
179 | } |
180 | |
181 | })); |
182 | |
183 | === modified file 'lib/lp/app/javascript/tests/test_beta_notification.js' |
184 | --- lib/lp/app/javascript/tests/test_beta_notification.js 2012-02-07 20:20:59 +0000 |
185 | +++ lib/lp/app/javascript/tests/test_beta_notification.js 2012-04-04 05:02:23 +0000 |
186 | @@ -39,7 +39,7 @@ |
187 | |
188 | test_library_exists: function () { |
189 | Y.Assert.isObject(Y.lp.app.beta_features, |
190 | - "We should be able to locate the lp.app.beta_features module"); |
191 | + "Could not locate the lp.app.beta_features module"); |
192 | }, |
193 | |
194 | test_beta_banner_one_beta_feature: function() { |
195 | |
196 | === modified file 'lib/lp/bugs/javascript/bugtask_index.js' |
197 | --- lib/lp/bugs/javascript/bugtask_index.js 2012-03-21 01:26:18 +0000 |
198 | +++ lib/lp/bugs/javascript/bugtask_index.js 2012-04-04 05:02:23 +0000 |
199 | @@ -742,7 +742,8 @@ |
200 | var delete_text_template = [ |
201 | '<p class="large-warning" style="padding:2px 2px 0 36px;">', |
202 | ' You are about to mark bug "{bug}"<br>as no longer affecting', |
203 | - ' {target}.<br><br>', |
204 | + ' {target}.', |
205 | + '</p><p>', |
206 | ' <strong>Please confirm you really want to do this.</strong>', |
207 | '</p>' |
208 | ].join(''); |
209 | |
210 | === modified file 'lib/lp/registry/browser/pillar.py' |
211 | --- lib/lp/registry/browser/pillar.py 2012-03-31 11:32:15 +0000 |
212 | +++ lib/lp/registry/browser/pillar.py 2012-04-04 05:02:23 +0000 |
213 | @@ -17,6 +17,7 @@ |
214 | |
215 | from lazr.restful import ResourceJSONEncoder |
216 | from lazr.restful.interfaces import IJSONRequestCache |
217 | +from lazr.restful.utils import get_current_web_service_request |
218 | import simplejson |
219 | from zope.component import getUtility |
220 | from zope.interface import ( |
221 | @@ -26,6 +27,7 @@ |
222 | from zope.schema.interfaces import IVocabulary |
223 | from zope.schema.vocabulary import getVocabularyRegistry |
224 | from zope.security.interfaces import Unauthorized |
225 | +from zope.traversing.browser.absoluteurl import absoluteURL |
226 | |
227 | from lp.app.browser.launchpad import iter_view_registrations |
228 | from lp.app.browser.tales import MenuAPI |
229 | @@ -376,10 +378,25 @@ |
230 | self._loadSharedArtifacts() |
231 | |
232 | cache = IJSONRequestCache(self.request) |
233 | - branch_data = self._build_branch_template_data(self.branches) |
234 | - bug_data = self._build_bug_template_data(self.bugs) |
235 | + request = get_current_web_service_request() |
236 | + branch_data = self._build_branch_template_data(self.branches, request) |
237 | + bug_data = self._build_bug_template_data(self.bugs, request) |
238 | + sharee_data = { |
239 | + 'displayname': self.person.displayname, |
240 | + 'self_link': absoluteURL(self.person, request) |
241 | + } |
242 | + pillar_data = { |
243 | + 'self_link': absoluteURL(self.pillar, request) |
244 | + } |
245 | + cache.objects['sharee'] = sharee_data |
246 | + cache.objects['pillar'] = pillar_data |
247 | cache.objects['bugs'] = bug_data |
248 | cache.objects['branches'] = branch_data |
249 | + enabled_writable_flag = ( |
250 | + 'disclosure.enhanced_sharing.writable') |
251 | + write_flag_enabled = bool(getFeatureFlag(enabled_writable_flag)) |
252 | + cache.objects['sharing_write_enabled'] = (write_flag_enabled |
253 | + and check_permission('launchpad.Edit', self.pillar)) |
254 | |
255 | def _loadSharedArtifacts(self): |
256 | bugs = [] |
257 | @@ -397,31 +414,35 @@ |
258 | self.shared_bugs_count = len(bugs) |
259 | self.shared_branches_count = len(branches) |
260 | |
261 | - def _build_branch_template_data(self, branches): |
262 | + def _build_branch_template_data(self, branches, request): |
263 | branch_data = [] |
264 | for branch in branches: |
265 | branch_data.append(dict( |
266 | - branch_link=canonical_url(branch), |
267 | + self_link=absoluteURL(branch, request), |
268 | + web_link=canonical_url(branch, path_only_if_possible=True), |
269 | branch_name=branch.unique_name, |
270 | branch_id=branch.id)) |
271 | return branch_data |
272 | |
273 | - def _build_bug_template_data(self, bugs): |
274 | + def _build_bug_template_data(self, bugs, request): |
275 | bug_data = [] |
276 | for bug in bugs: |
277 | [bugtask] = [task for task in bug.bugtasks if |
278 | task.target == self.pillar] |
279 | if bugtask is not None: |
280 | - url = canonical_url(bugtask, path_only_if_possible=True) |
281 | + web_link = canonical_url(bugtask, path_only_if_possible=True) |
282 | + self_link = absoluteURL(bugtask, request) |
283 | importance = bugtask.importance.title.lower() |
284 | else: |
285 | # This shouldn't ever happen, but if it does there's no reason |
286 | # to crash. |
287 | - url = canonical_url(bug, path_only_if_possible=True) |
288 | + web_link = canonical_url(bug, path_only_if_possible=True) |
289 | + self_link = absoluteURL(bug, request) |
290 | importance = bug.default_bugtask.importance.title.lower() |
291 | |
292 | bug_data.append(dict( |
293 | - bug_link=url, |
294 | + self_link=self_link, |
295 | + web_link=web_link, |
296 | bug_summary=bug.title, |
297 | bug_id=bug.id, |
298 | bug_importance=importance)) |
299 | |
300 | === modified file 'lib/lp/registry/browser/tests/test_pillar_sharing.py' |
301 | --- lib/lp/registry/browser/tests/test_pillar_sharing.py 2012-03-31 11:32:15 +0000 |
302 | +++ lib/lp/registry/browser/tests/test_pillar_sharing.py 2012-04-04 05:02:23 +0000 |
303 | @@ -7,6 +7,7 @@ |
304 | |
305 | from BeautifulSoup import BeautifulSoup |
306 | from lazr.restful.interfaces import IJSONRequestCache |
307 | +from lazr.restful.utils import get_current_web_service_request |
308 | import simplejson |
309 | from testtools.matchers import ( |
310 | LessThan, |
311 | @@ -17,6 +18,7 @@ |
312 | from zope.component import getUtility |
313 | from zope.publisher.interfaces import NotFound |
314 | from zope.security.interfaces import Unauthorized |
315 | +from zope.traversing.browser.absoluteurl import absoluteURL |
316 | |
317 | from lp.app.interfaces.services import IService |
318 | from lp.registry.enums import InformationType |
319 | @@ -41,6 +43,9 @@ |
320 | |
321 | |
322 | DETAILS_ENABLED_FLAG = {'disclosure.enhanced_sharing_details.enabled': 'true'} |
323 | +DETAILS_WRITE_FLAG = { |
324 | + 'disclosure.enhanced_sharing_details.enabled': 'true', |
325 | + 'disclosure.enhanced_sharing.writable': 'true'} |
326 | ENABLED_FLAG = {'disclosure.enhanced_sharing.enabled': 'true'} |
327 | WRITE_FLAG = {'disclosure.enhanced_sharing.writable': 'true'} |
328 | |
329 | @@ -55,21 +60,34 @@ |
330 | person = self.factory.makePerson() |
331 | if with_sharing: |
332 | if self.pillar_type == 'product': |
333 | - bug = self.factory.makeBug( |
334 | + self.bug = self.factory.makeBug( |
335 | + product=self.pillar, |
336 | + owner=self.pillar.owner, |
337 | + private=True) |
338 | + self.branch = self.factory.makeBranch( |
339 | product=self.pillar, |
340 | owner=self.pillar.owner, |
341 | private=True) |
342 | elif self.pillar_type == 'distribution': |
343 | - bug = self.factory.makeBug( |
344 | + self.branch = None |
345 | + self.bug = self.factory.makeBug( |
346 | distribution=self.pillar, |
347 | owner=self.pillar.owner, |
348 | private=True) |
349 | - artifact = self.factory.makeAccessArtifact(concrete=bug) |
350 | + artifact = self.factory.makeAccessArtifact(concrete=self.bug) |
351 | policy = self.factory.makeAccessPolicy(pillar=self.pillar) |
352 | self.factory.makeAccessPolicyArtifact( |
353 | artifact=artifact, policy=policy) |
354 | self.factory.makeAccessArtifactGrant( |
355 | artifact=artifact, grantee=person, grantor=self.pillar.owner) |
356 | + if self.branch: |
357 | + artifact = self.factory.makeAccessArtifact( |
358 | + concrete=self.branch) |
359 | + self.factory.makeAccessPolicyArtifact( |
360 | + artifact=artifact, policy=policy) |
361 | + self.factory.makeAccessArtifactGrant( |
362 | + artifact=artifact, grantee=person, |
363 | + grantor=self.pillar.owner) |
364 | |
365 | return PillarPerson(self.pillar, person) |
366 | |
367 | @@ -110,6 +128,54 @@ |
368 | view = create_initialized_view(pillarperson, '+index') |
369 | self.assertEqual(pillarperson.person.displayname, view.page_title) |
370 | |
371 | + def test_view_data_model(self): |
372 | + # Test that the json request cache contains the view data model. |
373 | + with FeatureFixture(DETAILS_ENABLED_FLAG): |
374 | + pillarperson = self.getPillarPerson() |
375 | + view = create_initialized_view(pillarperson, '+index') |
376 | + cache = IJSONRequestCache(view.request) |
377 | + request = get_current_web_service_request() |
378 | + self.assertEqual({ |
379 | + 'self_link': absoluteURL(pillarperson.person, request), |
380 | + 'displayname': pillarperson.person.displayname |
381 | + }, cache.objects.get('sharee')) |
382 | + self.assertEqual({ |
383 | + 'self_link': absoluteURL(pillarperson.pillar, request), |
384 | + }, cache.objects.get('pillar')) |
385 | + bugtask = self.bug.default_bugtask |
386 | + self.assertEqual({ |
387 | + 'bug_id': self.bug.id, |
388 | + 'bug_summary': self.bug.title, |
389 | + 'bug_importance': bugtask.importance.title.lower(), |
390 | + 'web_link': canonical_url( |
391 | + bugtask, path_only_if_possible=True), |
392 | + 'self_link': absoluteURL(bugtask, request), |
393 | + }, cache.objects.get('bugs')[0]) |
394 | + if self.pillar_type == 'product': |
395 | + self.assertEqual({ |
396 | + 'branch_id': self.branch.id, |
397 | + 'branch_name': self.branch.unique_name, |
398 | + 'web_link': canonical_url( |
399 | + self.branch, path_only_if_possible=True), |
400 | + 'self_link': absoluteURL(self.branch, request), |
401 | + }, cache.objects.get('branches')[0]) |
402 | + |
403 | + def test_view_write_enabled_without_feature_flag(self): |
404 | + # Test that sharing_write_enabled is not set without the feature flag. |
405 | + with FeatureFixture(DETAILS_ENABLED_FLAG): |
406 | + pillarperson = self.getPillarPerson() |
407 | + view = create_initialized_view(pillarperson, '+index') |
408 | + cache = IJSONRequestCache(view.request) |
409 | + self.assertFalse(cache.objects.get('sharing_write_enabled')) |
410 | + |
411 | + def test_view_write_enabled_with_feature_flag(self): |
412 | + # Test that sharing_write_enabled is set when required. |
413 | + with FeatureFixture(DETAILS_WRITE_FLAG): |
414 | + pillarperson = self.getPillarPerson() |
415 | + view = create_initialized_view(pillarperson, '+index') |
416 | + cache = IJSONRequestCache(view.request) |
417 | + self.assertTrue(cache.objects.get('sharing_write_enabled')) |
418 | + |
419 | |
420 | class TestProductSharingDetailsView( |
421 | TestCaseWithFactory, PillarSharingDetailsMixin): |
422 | |
423 | === modified file 'lib/lp/registry/javascript/sharing/pillarsharingview.js' |
424 | --- lib/lp/registry/javascript/sharing/pillarsharingview.js 2012-03-31 11:32:15 +0000 |
425 | +++ lib/lp/registry/javascript/sharing/pillarsharingview.js 2012-04-04 05:02:23 +0000 |
426 | @@ -182,9 +182,9 @@ |
427 | */ |
428 | confirm_sharee_removal: function(delete_link, person_uri, person_name) { |
429 | var confirm_text_template = [ |
430 | - '<p class="large-warning" style="padding:2px 2px 0 36px;">', |
431 | + '<p class="large-warning" style="padding:2px 2px 15px 36px;">', |
432 | ' Do you really want to stop sharing', |
433 | - ' "{pillar}" with {person_name}?<br><br>', |
434 | + ' "{pillar}" with {person_name}?', |
435 | '</p>' |
436 | ].join(''); |
437 | var confirm_text = Y.Lang.sub(confirm_text_template, |
438 | |
439 | === modified file 'lib/lp/registry/javascript/sharing/sharingdetails.js' |
440 | --- lib/lp/registry/javascript/sharing/sharingdetails.js 2012-03-28 22:21:37 +0000 |
441 | +++ lib/lp/registry/javascript/sharing/sharingdetails.js 2012-04-04 05:02:23 +0000 |
442 | @@ -3,12 +3,18 @@ |
443 | * |
444 | * Sharing details widget |
445 | * |
446 | - * @module lp.registry.sharing.details |
447 | + * @module lp.registry.sharing.sharingdetails |
448 | */ |
449 | |
450 | -YUI.add('lp.registry.sharing.details', function(Y) { |
451 | - |
452 | -var namespace = Y.namespace('lp.registry.sharing.details'); |
453 | +YUI.add('lp.registry.sharing.sharingdetails', function(Y) { |
454 | + |
455 | +var namespace = Y.namespace('lp.registry.sharing.sharingdetails'); |
456 | + |
457 | +var |
458 | + NAME = "sharingDetailsTable", |
459 | + // Events |
460 | + REMOVE_GRANT = 'removeGrant'; |
461 | + |
462 | /* |
463 | * Sharing details table widget. |
464 | * This widget displays the details of a specific person's shared artifacts. |
465 | @@ -18,7 +24,12 @@ |
466 | } |
467 | |
468 | SharingDetailsTable.ATTRS = { |
469 | - |
470 | + // The node holding the details table. |
471 | + details_table_body: { |
472 | + getter: function() { |
473 | + return Y.one('#sharing-table-body'); |
474 | + } |
475 | + }, |
476 | table_body_template: { |
477 | value: null |
478 | }, |
479 | @@ -37,20 +48,20 @@ |
480 | |
481 | branches: { |
482 | value: [] |
483 | + }, |
484 | + |
485 | + write_enabled: { |
486 | + value: false |
487 | + }, |
488 | + |
489 | + person_name: { |
490 | + value: null |
491 | } |
492 | }; |
493 | |
494 | Y.extend(SharingDetailsTable, Y.Widget, { |
495 | |
496 | initializer: function(config) { |
497 | - if (Y.Lang.isValue(config.branches)) { |
498 | - this.set('branches', config.branches); |
499 | - } |
500 | - |
501 | - if (Y.Lang.isValue(config.bugs)) { |
502 | - this.set('bugs', config.bugs); |
503 | - } |
504 | - |
505 | this.set( |
506 | 'bug_details_row_template', |
507 | this._bug_details_row_template()); |
508 | @@ -62,6 +73,7 @@ |
509 | this.set( |
510 | 'table_body_template', |
511 | this._table_body_template()); |
512 | + this.publish(REMOVE_GRANT); |
513 | }, |
514 | |
515 | renderUI: function() { |
516 | @@ -74,37 +86,75 @@ |
517 | var template = this.get('table_body_template'); |
518 | var html = Y.lp.mustache.to_html( |
519 | template, |
520 | - {branches: branch_data, bugs: bug_data}, |
521 | + {branches: branch_data, bugs: bug_data, |
522 | + displayname: this.get('person_name')}, |
523 | partials); |
524 | - var table = Y.one('#sharing-table-body'); |
525 | - table.set('innerHTML', html); |
526 | - }, |
527 | + |
528 | + var details_table_body = this.get('details_table_body'); |
529 | + var table_body_node = Y.Node.create(html); |
530 | + details_table_body.replace(table_body_node); |
531 | + this._update_editable_status(); |
532 | + }, |
533 | + |
534 | + _update_editable_status: function() { |
535 | + var details_table_body = this.get('details_table_body'); |
536 | + if (!this.get('write_enabled')) { |
537 | + details_table_body.all('.sprite.remove').each(function(node) { |
538 | + node.addClass('unseen'); |
539 | + }); |
540 | + } |
541 | + }, |
542 | + |
543 | + bindUI: function() { |
544 | + // Bind the delete links. |
545 | + if (!this.get('write_enabled')) { |
546 | + return; |
547 | + } |
548 | + var details_table_body = this.get('details_table_body'); |
549 | + var self = this; |
550 | + details_table_body.delegate('click', function(e) { |
551 | + e.halt(); |
552 | + var delete_link = e.currentTarget; |
553 | + var artifact_uri = delete_link.getAttribute('data-self_link'); |
554 | + var artifact_name = delete_link.getAttribute('data-name'); |
555 | + var artifact_type = delete_link.getAttribute('data-type'); |
556 | + self.fire( |
557 | + REMOVE_GRANT, delete_link, artifact_uri, artifact_name, |
558 | + artifact_type); |
559 | + }, 'span[id^=remove-] a'); |
560 | + }, |
561 | |
562 | _table_body_template: function() { |
563 | return [ |
564 | + '<tbody id="sharing-table-body">', |
565 | '{{#branches}}', |
566 | '{{> branch}}', |
567 | '{{/branches}}', |
568 | '{{#bugs}}', |
569 | '{{> bug}}', |
570 | - '{{/bugs}}' |
571 | + '{{/bugs}}', |
572 | + '</tbody>' |
573 | ].join(' '); |
574 | }, |
575 | |
576 | _bug_details_row_template: function() { |
577 | return [ |
578 | - '<tr>', |
579 | + '<tr id="shared-bug-{{ bug_id }}">', |
580 | ' <td class="icon right">', |
581 | - ' <span class="sprite bug-{{ bug_importance }}"></span>', |
582 | + ' <span class="sprite bug-{{bug_importance}}"> </span>', |
583 | ' </td>', |
584 | - ' <td class="amount">{{ bug_id }}</td>', |
585 | + ' <td class="amount">{{bug_id}}</td>', |
586 | ' <td>', |
587 | - ' <a href="{{ bug_link }}">{{ bug_summary }}</a>', |
588 | + ' <a href="{{web_link}}">{{bug_summary}}</a>', |
589 | ' </td>', |
590 | - ' <td>—</td>', |
591 | - ' <td class="actions" id="remove-bug-{{ bug_id }}">', |
592 | - ' <a class="sprite remove" href="#"', |
593 | - ' title="Unshare this with the user"> </a>', |
594 | + ' <td class="action-icons nowrap">', |
595 | + ' <span id="remove-bug-{{ bug_id }}">', |
596 | + ' <a class="sprite remove" href="#"', |
597 | + ' title="Unshare bug {{bug_id}} with {{displayname}}"', |
598 | + ' data-self_link="{{self_link}}" data-name="Bug {{bug_id}}"', |
599 | + ' data-type="bug">', |
600 | + ' </a>', |
601 | + ' </span>', |
602 | ' </td>', |
603 | '</tr>' |
604 | ].join(' '); |
605 | @@ -112,27 +162,31 @@ |
606 | |
607 | _branch_details_row_template: function() { |
608 | return [ |
609 | - '<tr>', |
610 | + '<tr id="shared-branch-{{ branch_id }}">', |
611 | ' <td colspan="3">', |
612 | - ' <a class="sprite branch" href="{{ branch_link }}">', |
613 | - ' {{ branch_name }}', |
614 | + ' <a class="sprite branch" href="{{web_link}}">', |
615 | + ' {{branch_name}}', |
616 | ' </a>', |
617 | ' </td>', |
618 | - ' <td>—</td>', |
619 | - ' <td class="actions" id="remove-branch-{{ branch_id }}">', |
620 | - ' <a class="sprite remove" href="#"', |
621 | - ' title="Unshare this with the user"> </a>', |
622 | + ' <td class="action-icons nowrap">', |
623 | + ' <span id="remove-branch-{{branch_id}}">', |
624 | + ' <a class="sprite remove" href="#"', |
625 | + ' title="Unshare branch {{branch_name}} with {{displayname}}"', |
626 | + ' data-self_link="{{self_link}}" data-name="{{branch_name}}"', |
627 | + ' data-type="branch">', |
628 | + ' </a>', |
629 | + ' </span>', |
630 | ' </td>', |
631 | '</tr>' |
632 | ].join(' '); |
633 | } |
634 | }); |
635 | |
636 | -SharingDetailsTable.NAME = 'sharingDetailsTable'; |
637 | +SharingDetailsTable.NAME = NAME; |
638 | +SharingDetailsTable.REMOVE_GRANT = REMOVE_GRANT; |
639 | |
640 | namespace.SharingDetailsTable = SharingDetailsTable; |
641 | |
642 | }, "0.1", { "requires": [ |
643 | - 'node', |
644 | - 'lp.mustache' |
645 | + 'node', 'event', 'lp.mustache' |
646 | ] }); |
647 | |
648 | === added file 'lib/lp/registry/javascript/sharing/sharingdetailsview.js' |
649 | --- lib/lp/registry/javascript/sharing/sharingdetailsview.js 1970-01-01 00:00:00 +0000 |
650 | +++ lib/lp/registry/javascript/sharing/sharingdetailsview.js 2012-04-04 05:02:23 +0000 |
651 | @@ -0,0 +1,202 @@ |
652 | +/* Copyright 2012 Canonical Ltd. This software is licensed under the |
653 | + * GNU Affero General Public License version 3 (see the file LICENSE). |
654 | + * |
655 | + * Disclosure infrastructure. |
656 | + * |
657 | + * @module lp.registry.sharing |
658 | + */ |
659 | + |
660 | +YUI.add('lp.registry.sharing.sharingdetailsview', function(Y) { |
661 | + |
662 | +var namespace = Y.namespace('lp.registry.sharing.sharingdetailsview'); |
663 | + |
664 | +function SharingDetailsView(config) { |
665 | + SharingDetailsView.superclass.constructor.apply(this, arguments); |
666 | +} |
667 | + |
668 | +SharingDetailsView.ATTRS = { |
669 | + lp_client: { |
670 | + value: new Y.lp.client.Launchpad() |
671 | + }, |
672 | + |
673 | + write_enabled: { |
674 | + value: false |
675 | + }, |
676 | + |
677 | + sharing_details_table: { |
678 | + value: null |
679 | + } |
680 | +}; |
681 | + |
682 | +Y.extend(SharingDetailsView, Y.Widget, { |
683 | + |
684 | + initializer: function(config) { |
685 | + if (LP.cache.sharing_write_enabled !== true) { |
686 | + return; |
687 | + } |
688 | + this.set('write_enabled', true); |
689 | + }, |
690 | + |
691 | + renderUI: function() { |
692 | + var ns = Y.lp.registry.sharing.sharingdetails; |
693 | + var details_table = new ns.SharingDetailsTable({ |
694 | + bugs: LP.cache.bugs, |
695 | + branches: LP.cache.branches, |
696 | + person_name: LP.cache.sharee.displayname, |
697 | + write_enabled: this.get('write_enabled') |
698 | + }); |
699 | + this.set('sharing_details_table', details_table); |
700 | + details_table.render(); |
701 | + }, |
702 | + |
703 | + bindUI: function() { |
704 | + if (!this.get('write_enabled')) { |
705 | + return; |
706 | + } |
707 | + var self = this; |
708 | + var sharing_details_table = this.get('sharing_details_table'); |
709 | + var ns = Y.lp.registry.sharing.sharingdetails; |
710 | + sharing_details_table.subscribe( |
711 | + ns.SharingDetailsTable.REMOVE_GRANT, function(e) { |
712 | + self.confirm_grant_removal( |
713 | + e.details[0], e.details[1], e.details[2], e.details[3]); |
714 | + }); |
715 | + }, |
716 | + |
717 | + syncUI: function() { |
718 | + var sharing_details_table = this.get('sharing_details_table'); |
719 | + sharing_details_table.syncUI(); |
720 | + }, |
721 | + |
722 | + /** |
723 | + * Show a spinner next to the delete icon. |
724 | + * |
725 | + * @method _show_delete_spinner |
726 | + */ |
727 | + _show_delete_spinner: function(delete_link) { |
728 | + var spinner_node = Y.Node.create( |
729 | + '<img class="spinner" src="/@@/spinner" alt="Removing..." />'); |
730 | + delete_link.insertBefore(spinner_node, delete_link); |
731 | + delete_link.addClass('unseen'); |
732 | + }, |
733 | + |
734 | + /** |
735 | + * Hide the delete spinner. |
736 | + * |
737 | + * @method _hide_delete_spinner |
738 | + */ |
739 | + _hide_delete_spinner: function(delete_link) { |
740 | + delete_link.removeClass('unseen'); |
741 | + var spinner = delete_link.get('parentNode').one('.spinner'); |
742 | + if (Y.Lang.isValue(spinner)) { |
743 | + spinner.remove(); |
744 | + } |
745 | + }, |
746 | + |
747 | + /** |
748 | + * Prompt the user to confirm the removal of access to the selected |
749 | + * artifact. |
750 | + * |
751 | + * @method confirm_grant_removal |
752 | + * @param delete_link |
753 | + * @param artifact_uri |
754 | + * @param artifact_name |
755 | + * @param artifact_type |
756 | + */ |
757 | + confirm_grant_removal: function(delete_link, artifact_uri, |
758 | + artifact_name, artifact_type) { |
759 | + var confirm_text_template = [ |
760 | + '<p class="large-warning" style="padding:2px 2px 15px 36px;">', |
761 | + ' Do you really want to stop sharing', |
762 | + ' "{artifact}" with {person_name}?', |
763 | + '</p>' |
764 | + ].join(''); |
765 | + var person_name = LP.cache.sharee.displayname; |
766 | + var confirm_text = Y.Lang.sub(confirm_text_template, |
767 | + {artifact: artifact_name, |
768 | + person_name: person_name}); |
769 | + var self = this; |
770 | + var co = new Y.lp.app.confirmationoverlay.ConfirmationOverlay({ |
771 | + submit_fn: function() { |
772 | + self.perform_remove_grant( |
773 | + delete_link, artifact_uri, artifact_type); |
774 | + }, |
775 | + form_content: confirm_text, |
776 | + headerContent: '<h2>Stop sharing</h2>' |
777 | + }); |
778 | + co.show(); |
779 | + }, |
780 | + |
781 | + /** |
782 | + * The server call to remove the specified sharee has succeeded. |
783 | + * Update the model and view. |
784 | + * @method remove_grant_success |
785 | + * @param artifact_uri |
786 | + */ |
787 | + remove_grant_success: function(artifact_uri) { |
788 | + var bugs_data = LP.cache.bugs; |
789 | + var self = this; |
790 | + Y.Array.some(bugs_data, function(bug, index) { |
791 | + if (bug.self_link === artifact_uri) { |
792 | + bugs_data.splice(index, 1); |
793 | + self.syncUI(); |
794 | + return true; |
795 | + } |
796 | + }); |
797 | + var branch_data = LP.cache.branches; |
798 | + Y.Array.some(branch_data, function(branch, index) { |
799 | + if (branch.self_link === artifact_uri) { |
800 | + branch_data.splice(index, 1); |
801 | + self.syncUI(); |
802 | + return true; |
803 | + } |
804 | + }); |
805 | + }, |
806 | + |
807 | + /** |
808 | + * Make a server call to remove access to the specified artifact. |
809 | + * @method perform_remove_sharee |
810 | + * @param delete_link |
811 | + * @param artifact_uri |
812 | + * @param artifact_type |
813 | + */ |
814 | + perform_remove_grant: function(delete_link, artifact_uri, artifact_type) { |
815 | + var error_handler = new Y.lp.client.ErrorHandler(); |
816 | + var bugs = []; |
817 | + var branches = []; |
818 | + if (artifact_type === 'bug') { |
819 | + bugs = [artifact_uri]; |
820 | + } else { |
821 | + branches = [artifact_uri]; |
822 | + } |
823 | + var self = this; |
824 | + var y_config = { |
825 | + on: { |
826 | + start: Y.bind( |
827 | + self._show_delete_spinner, namespace, delete_link), |
828 | + end: Y.bind(self._hide_delete_spinner, namespace, delete_link), |
829 | + success: function() { |
830 | + self.remove_grant_success(artifact_uri); |
831 | + }, |
832 | + failure: error_handler.getFailureHandler() |
833 | + }, |
834 | + parameters: { |
835 | + pillar: LP.cache.pillar.self_link, |
836 | + sharee: LP.cache.sharee.self_link, |
837 | + bugs: bugs, |
838 | + branches: branches |
839 | + } |
840 | + }; |
841 | + this.get('lp_client').named_post( |
842 | + '/+services/sharing', 'revokeAccessGrants', y_config); |
843 | + } |
844 | +}); |
845 | + |
846 | +SharingDetailsView.NAME = 'sharingDetailsView'; |
847 | +namespace.SharingDetailsView = SharingDetailsView; |
848 | + |
849 | +}, "0.1", { "requires": [ |
850 | + 'node', 'selector-css3', 'lp.client', 'lp.mustache', |
851 | + 'lp.registry.sharing.sharingdetails', 'lp.app.confirmationoverlay' |
852 | + ]}); |
853 | + |
854 | |
855 | === modified file 'lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js' |
856 | --- lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js 2012-03-31 11:32:15 +0000 |
857 | +++ lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js 2012-04-04 05:02:23 +0000 |
858 | @@ -60,7 +60,7 @@ |
859 | |
860 | test_library_exists: function () { |
861 | Y.Assert.isObject(Y.lp.registry.sharing.pillarsharingview, |
862 | - "We should be able to locate the " + |
863 | + "Could not locate the " + |
864 | "lp.registry.sharing.pillarsharingview module"); |
865 | }, |
866 | |
867 | |
868 | === modified file 'lib/lp/registry/javascript/sharing/tests/test_shareelisting_navigator.js' |
869 | --- lib/lp/registry/javascript/sharing/tests/test_shareelisting_navigator.js 2012-03-20 06:11:07 +0000 |
870 | +++ lib/lp/registry/javascript/sharing/tests/test_shareelisting_navigator.js 2012-04-04 05:02:23 +0000 |
871 | @@ -36,7 +36,7 @@ |
872 | |
873 | test_library_exists: function () { |
874 | Y.Assert.isObject(Y.lp.registry.sharing.shareelisting_navigator, |
875 | - "We should be able to locate the " + |
876 | + "Could not locate the " + |
877 | "lp.registry.sharing.shareelisting_navigator module"); |
878 | }, |
879 | |
880 | |
881 | === modified file 'lib/lp/registry/javascript/sharing/tests/test_shareepicker.js' |
882 | --- lib/lp/registry/javascript/sharing/tests/test_shareepicker.js 2012-03-27 02:27:21 +0000 |
883 | +++ lib/lp/registry/javascript/sharing/tests/test_shareepicker.js 2012-04-04 05:02:23 +0000 |
884 | @@ -76,7 +76,7 @@ |
885 | |
886 | test_library_exists: function () { |
887 | Y.Assert.isObject(Y.lp.registry.sharing.shareepicker, |
888 | - "We should be able to locate the " + |
889 | + "Could not locate the " + |
890 | "lp.registry.sharing module"); |
891 | }, |
892 | |
893 | |
894 | === modified file 'lib/lp/registry/javascript/sharing/tests/test_shareetable.js' |
895 | --- lib/lp/registry/javascript/sharing/tests/test_shareetable.js 2012-04-02 23:55:58 +0000 |
896 | +++ lib/lp/registry/javascript/sharing/tests/test_shareetable.js 2012-04-04 05:02:23 +0000 |
897 | @@ -69,7 +69,7 @@ |
898 | |
899 | test_library_exists: function () { |
900 | Y.Assert.isObject(Y.lp.registry.sharing.shareetable, |
901 | - "We should be able to locate the " + |
902 | + "Could not locate the " + |
903 | "lp.registry.sharing.shareetable module"); |
904 | }, |
905 | |
906 | |
907 | === renamed file 'lib/lp/registry/javascript/sharing/tests/test_sharing_details.html' => 'lib/lp/registry/javascript/sharing/tests/test_sharingdetails.html' |
908 | --- lib/lp/registry/javascript/sharing/tests/test_sharing_details.html 2012-03-27 15:10:21 +0000 |
909 | +++ lib/lp/registry/javascript/sharing/tests/test_sharingdetails.html 2012-04-04 05:02:23 +0000 |
910 | @@ -34,18 +34,20 @@ |
911 | <script type="text/javascript" src="../sharingdetails.js"></script> |
912 | |
913 | <!-- The test suite. --> |
914 | - <script type="text/javascript" src="test_sharing_details.js"></script> |
915 | + <script type="text/javascript" src="test_sharingdetails.js"></script> |
916 | |
917 | </head> |
918 | <body class="yui3-skin-sam"> |
919 | <!-- The example markup required by the script to run --> |
920 | <ul id="suites"> |
921 | - <li>lp.registry.sharing.details.test</li> |
922 | + <li>lp.registry.sharing.sharingdetails.test</li> |
923 | </ul> |
924 | - <table> |
925 | - <tbody id="sharing-table-body"> |
926 | - </tbody> |
927 | - </table> |
928 | - |
929 | + <div id="fixture"></div> |
930 | + <script type="text/x-template" id="sharing-table-template"> |
931 | + <table> |
932 | + <tbody id="sharing-table-body"> |
933 | + </tbody> |
934 | + </table> |
935 | + </script> |
936 | </body> |
937 | </html> |
938 | |
939 | === renamed file 'lib/lp/registry/javascript/sharing/tests/test_sharing_details.js' => 'lib/lp/registry/javascript/sharing/tests/test_sharingdetails.js' |
940 | --- lib/lp/registry/javascript/sharing/tests/test_sharing_details.js 2012-03-27 20:45:36 +0000 |
941 | +++ lib/lp/registry/javascript/sharing/tests/test_sharingdetails.js 2012-04-04 05:02:23 +0000 |
942 | @@ -1,70 +1,173 @@ |
943 | /* Copyright (c) 2012, Canonical Ltd. All rights reserved. */ |
944 | -YUI.add('lp.registry.sharing.details.test', function(Y) { |
945 | +YUI.add('lp.registry.sharing.sharingdetails.test', function(Y) { |
946 | |
947 | // Local aliases |
948 | - var Assert = Y.Assert, |
949 | - ArrayAssert = Y.ArrayAssert; |
950 | - var sharing_details = Y.lp.registry.sharing.details; |
951 | + var Assert = Y.Assert; |
952 | + var sharing_details = Y.lp.registry.sharing.sharingdetails; |
953 | |
954 | - var tests = Y.namespace('lp.registry.sharing.details.test'); |
955 | + var tests = Y.namespace('lp.registry.sharing.sharingdetails.test'); |
956 | tests.suite = new Y.Test.Suite( |
957 | - "lp.registry.sharing.details Tests"); |
958 | + "lp.registry.sharing.sharingdetails Tests"); |
959 | |
960 | tests.suite.add(new Y.Test.Case({ |
961 | name: 'Sharing Details', |
962 | |
963 | - setUp: function() { |
964 | + setUp: function () { |
965 | window.LP = { |
966 | links: {}, |
967 | - cache: {} |
968 | + cache: { |
969 | + bugs: [ |
970 | + { |
971 | + self_link: 'api/devel/bugs/2', |
972 | + web_link:'/bugs/2', |
973 | + bug_id: '2', |
974 | + bug_importance: 'critical', |
975 | + bug_summary:'Everything is broken.' |
976 | + } |
977 | + ], |
978 | + branches: [ |
979 | + { |
980 | + self_link: 'api/devel/~someone/+junk/somebranch', |
981 | + web_link:'/~someone/+junk/somebranch', |
982 | + branch_id: '2', |
983 | + branch_name:'lp:~someone/+junk/somebranch' |
984 | + } |
985 | + ] |
986 | + } |
987 | }; |
988 | - }, |
989 | - |
990 | - tearDown: function() { |
991 | - }, |
992 | - |
993 | + this.fixture = Y.one('#fixture'); |
994 | + var sharing_table = Y.Node.create( |
995 | + Y.one('#sharing-table-template').getContent()); |
996 | + this.fixture.appendChild(sharing_table); |
997 | + |
998 | + }, |
999 | + |
1000 | + tearDown: function () { |
1001 | + if (this.fixture !== null) { |
1002 | + this.fixture.empty(true); |
1003 | + } |
1004 | + delete this.fixture; |
1005 | + delete window.LP; |
1006 | + }, |
1007 | + |
1008 | + _create_Widget: function(overrides) { |
1009 | + if (!Y.Lang.isValue(overrides)) { |
1010 | + overrides = {}; |
1011 | + } |
1012 | + var config = Y.merge({ |
1013 | + person_name: 'Fred', |
1014 | + bugs: window.LP.cache.bugs, |
1015 | + branches: window.LP.cache.branches, |
1016 | + write_enabled: true |
1017 | + }, overrides); |
1018 | + window.LP.cache.sharee_data = config.sharees; |
1019 | + return new sharing_details.SharingDetailsTable(config); |
1020 | + }, |
1021 | + |
1022 | + test_library_exists: function () { |
1023 | + Y.Assert.isObject(Y.lp.registry.sharing.sharingdetails, |
1024 | + "Could not locate the " + |
1025 | + "lp.registry.sharing.sharingdetails module"); |
1026 | + }, |
1027 | + |
1028 | + test_widget_can_be_instantiated: function() { |
1029 | + this.details_widget = this._create_Widget(); |
1030 | + Y.Assert.isInstanceOf( |
1031 | + Y.lp.registry.sharing.sharingdetails.SharingDetailsTable, |
1032 | + this.details_widget, |
1033 | + "Sharing details table failed to be instantiated"); |
1034 | + }, |
1035 | + |
1036 | + // Read only mode disables the correct things. |
1037 | + test_readonly: function() { |
1038 | + this.details_widget = this._create_Widget({ |
1039 | + write_enabled: false |
1040 | + }); |
1041 | + this.details_widget.render(); |
1042 | + Y.all('#sharing-table-body .sprite.remove a') |
1043 | + .each(function(link) { |
1044 | + Y.Assert.isTrue(link.hasClass('unseen')); |
1045 | + }); |
1046 | + }, |
1047 | + |
1048 | + // Test that branches are correctly rendered. |
1049 | test_render_branches: function () { |
1050 | - var config = { |
1051 | - branches: [ |
1052 | - { |
1053 | - branch_link:'/~someone/+junk/somebranch', |
1054 | - branch_id: '2', |
1055 | - branch_name:'lp:~someone/+junk/somebranch' |
1056 | - } |
1057 | - ] |
1058 | - }; |
1059 | - details_module = Y.lp.registry.sharing.details; |
1060 | - table_constructor = details_module.SharingDetailsTable; |
1061 | - var details_widget = new table_constructor(config); |
1062 | - details_widget.render(); |
1063 | + this.details_widget = this._create_Widget(); |
1064 | + this.details_widget.render(); |
1065 | var expected = "lp:~someone/+junk/somebranch"; |
1066 | - var branch_link = Y.one('#sharing-table-body').one('a'); |
1067 | - var actual_text = branch_link.get('text').replace(/\s+/g, ''); |
1068 | + var web_link = Y.one( |
1069 | + '#sharing-table-body tr#shared-branch-2').one('a'); |
1070 | + var actual_text = web_link.get('text').replace(/\s+/g, ''); |
1071 | Assert.areEqual(expected, actual_text); |
1072 | }, |
1073 | |
1074 | + // Test that bugs are correctly rendered. |
1075 | test_render_bugs: function () { |
1076 | - var config = { |
1077 | - bugs: [ |
1078 | - { |
1079 | - bug_link:'/bugs/2', |
1080 | - bug_id: '2', |
1081 | - bug_importance: 'critical', |
1082 | - bug_summary:'Everything is broken.' |
1083 | - } |
1084 | - ] |
1085 | - }; |
1086 | - details_module = Y.lp.registry.sharing.details; |
1087 | - table_constructor = details_module.SharingDetailsTable; |
1088 | - var details_widget = new table_constructor(config); |
1089 | - details_widget.render(); |
1090 | + this.details_widget = this._create_Widget(); |
1091 | + this.details_widget.render(); |
1092 | var expected = "Everythingisbroken."; |
1093 | - var bug_link = Y.one('#sharing-table-body').one('a'); |
1094 | - var actual_text = bug_link.get('text').replace(/\s+/g, ''); |
1095 | + var web_link = Y.one( |
1096 | + '#sharing-table-body tr#shared-bug-2').one('a'); |
1097 | + var actual_text = web_link.get('text').replace(/\s+/g, ''); |
1098 | Assert.areEqual(expected, actual_text); |
1099 | + }, |
1100 | + |
1101 | + // When the bug revoke link is clicked, the correct event is published. |
1102 | + test_bug_revoke_click: function() { |
1103 | + this.details_widget = this._create_Widget(); |
1104 | + this.details_widget.render(); |
1105 | + var event_fired = false; |
1106 | + this.details_widget.subscribe( |
1107 | + sharing_details.SharingDetailsTable.REMOVE_GRANT, |
1108 | + function(e) { |
1109 | + var delete_link = e.details[0]; |
1110 | + var artifact_uri = e.details[1]; |
1111 | + var artifact_name = e.details[2]; |
1112 | + var artifact_type = e.details[3]; |
1113 | + Y.Assert.areEqual('api/devel/bugs/2', artifact_uri); |
1114 | + Y.Assert.areEqual('Bug 2', artifact_name); |
1115 | + Y.Assert.areEqual('bug', artifact_type); |
1116 | + Y.Assert.areEqual(delete_link_to_click, delete_link); |
1117 | + event_fired = true; |
1118 | + } |
1119 | + ); |
1120 | + var delete_link_to_click = |
1121 | + Y.one('#sharing-table-body span[id=remove-bug-2] a'); |
1122 | + delete_link_to_click.simulate('click'); |
1123 | + Y.Assert.isTrue(event_fired); |
1124 | + }, |
1125 | + |
1126 | + // When the branch revoke link is clicked, the correct event is |
1127 | + // published. |
1128 | + test_branch_revoke_click: function() { |
1129 | + this.details_widget = this._create_Widget(); |
1130 | + this.details_widget.render(); |
1131 | + var event_fired = false; |
1132 | + this.details_widget.subscribe( |
1133 | + sharing_details.SharingDetailsTable.REMOVE_GRANT, |
1134 | + function(e) { |
1135 | + var delete_link = e.details[0]; |
1136 | + var artifact_uri = e.details[1]; |
1137 | + var artifact_name = e.details[2]; |
1138 | + var artifact_type = e.details[3]; |
1139 | + Y.Assert.areEqual( |
1140 | + 'api/devel/~someone/+junk/somebranch', |
1141 | + artifact_uri); |
1142 | + Y.Assert.areEqual( |
1143 | + 'lp:~someone/+junk/somebranch', artifact_name); |
1144 | + Y.Assert.areEqual('branch', artifact_type); |
1145 | + Y.Assert.areEqual(delete_link_to_click, delete_link); |
1146 | + event_fired = true; |
1147 | + } |
1148 | + ); |
1149 | + var delete_link_to_click = |
1150 | + Y.one('#sharing-table-body span[id=remove-branch-2] a'); |
1151 | + delete_link_to_click.simulate('click'); |
1152 | + Y.Assert.isTrue(event_fired); |
1153 | } |
1154 | })); |
1155 | |
1156 | |
1157 | -}, '0.1', { 'requires': [ 'test', 'console', 'event', |
1158 | - 'lp.registry.sharing.details']}); |
1159 | +}, '0.1', { 'requires': |
1160 | + [ 'test', 'console', 'event', 'node-event-simulate', |
1161 | + 'lp.registry.sharing.sharingdetails']}); |
1162 | |
1163 | === added file 'lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.html' |
1164 | --- lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.html 1970-01-01 00:00:00 +0000 |
1165 | +++ lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.html 2012-04-04 05:02:23 +0000 |
1166 | @@ -0,0 +1,66 @@ |
1167 | +<!DOCTYPE html> |
1168 | +<!-- |
1169 | +Copyright 2012 Canonical Ltd. This software is licensed under the |
1170 | +GNU Affero General Public License version 3 (see the file LICENSE). |
1171 | +--> |
1172 | + |
1173 | +<html> |
1174 | + <head> |
1175 | + <title>Sharing Details View Tests</title> |
1176 | + |
1177 | + <!-- YUI and test setup --> |
1178 | + <script type="text/javascript" |
1179 | + src="../../../../../../build/js/yui/yui/yui.js"> |
1180 | + </script> |
1181 | + <link rel="stylesheet" |
1182 | + href="../../../../../../build/js/yui/console/assets/console-core.css" /> |
1183 | + <link rel="stylesheet" |
1184 | + href="../../../../../../build/js/yui/console/assets/skins/sam/console.css" /> |
1185 | + <link rel="stylesheet" |
1186 | + href="../../../../../../build/js/yui/test/assets/skins/sam/test.css" /> |
1187 | + |
1188 | + <script type="text/javascript" |
1189 | + src="../../../../../../build/js/lp/app/testing/testrunner.js"></script> |
1190 | + |
1191 | + <link rel="stylesheet" href="../../../../app/javascript/testing/test.css" /> |
1192 | + |
1193 | + <!-- Dependencies --> |
1194 | + <script type="text/javascript" |
1195 | + src="../../../../../../build/js/lp/app/testing/mockio.js"></script> |
1196 | + <script type="text/javascript" |
1197 | + src="../../../../../../build/js/lp/app/client.js"></script> |
1198 | + <script type="text/javascript" |
1199 | + src="../../../../../../build/js/lp/app/confirmationoverlay/confirmationoverlay.js"></script> |
1200 | + <script type="text/javascript" |
1201 | + src="../../../../../../build/js/lp/app/mustache.js"></script> |
1202 | + <script type="text/javascript" |
1203 | + src="../../../../../../build/js/lp/app/formoverlay/formoverlay.js"></script> |
1204 | + <script type="text/javascript" |
1205 | + src="../../../../../../build/js/lp/app/overlay/overlay.js"></script> |
1206 | + <script type="text/javascript" |
1207 | + src="../../../../../../build/js/lp/registry/sharing/sharingdetails.js"></script> |
1208 | + |
1209 | + <!-- The module under test. --> |
1210 | + <script type="text/javascript" src="../sharingdetailsview.js"></script> |
1211 | + |
1212 | + <!-- The test suite --> |
1213 | + <script type="text/javascript" src="test_sharingdetailsview.js"></script> |
1214 | + |
1215 | + <script id="test-fixture" type="text/x-template"> |
1216 | + <table id='sharing-details-table'></table> |
1217 | + </script> |
1218 | + </head> |
1219 | + <body class="yui3-skin-sam"> |
1220 | + <ul id="suites"> |
1221 | + <li>lp.registry.sharing.sharingdetailsview.test</li> |
1222 | + </ul> |
1223 | + <div id='fixture'> |
1224 | + </div> |
1225 | + <script type="text/x-template" id="sharing-table-template"> |
1226 | + <table> |
1227 | + <tbody id="sharing-table-body"> |
1228 | + </tbody> |
1229 | + </table> |
1230 | + </script> |
1231 | + </body> |
1232 | +</html> |
1233 | |
1234 | === added file 'lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js' |
1235 | --- lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js 1970-01-01 00:00:00 +0000 |
1236 | +++ lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js 2012-04-04 05:02:23 +0000 |
1237 | @@ -0,0 +1,305 @@ |
1238 | +/* Copyright (c) 2012, Canonical Ltd. All rights reserved. */ |
1239 | + |
1240 | +YUI.add('lp.registry.sharing.sharingdetailsview.test', function (Y) { |
1241 | + |
1242 | + var tests = Y.namespace('lp.registry.sharing.sharingdetailsview.test'); |
1243 | + tests.suite = new Y.Test.Suite( |
1244 | + 'lp.registry.sharing.sharingdetailsview Tests'); |
1245 | + |
1246 | + tests.suite.add(new Y.Test.Case({ |
1247 | + name: 'lp.registry.sharing.sharingdetailsview_tests', |
1248 | + |
1249 | + setUp: function () { |
1250 | + window.LP = { |
1251 | + links: {}, |
1252 | + cache: { |
1253 | + bugs: [ |
1254 | + { |
1255 | + self_link: 'api/devel/bugs/2', |
1256 | + web_link:'/bugs/2', |
1257 | + bug_id: '2', |
1258 | + bug_importance: 'critical', |
1259 | + bug_summary:'Everything is broken.' |
1260 | + } |
1261 | + ], |
1262 | + branches: [ |
1263 | + { |
1264 | + self_link: 'api/devel/~someone/+junk/somebranch', |
1265 | + web_link:'/~someone/+junk/somebranch', |
1266 | + branch_id: '2', |
1267 | + branch_name:'lp:~someone/+junk/somebranch' |
1268 | + } |
1269 | + ], |
1270 | + sharee: { |
1271 | + displayname: 'Fred Bloggs', |
1272 | + self_link: '~fred' |
1273 | + }, |
1274 | + pillar: { |
1275 | + self_link: '/pillar' |
1276 | + }, |
1277 | + sharing_write_enabled: true |
1278 | + } |
1279 | + }; |
1280 | + this.fixture = Y.one('#fixture'); |
1281 | + var sharee_table = Y.Node.create( |
1282 | + Y.one('#sharing-table-template').getContent()); |
1283 | + this.fixture.appendChild(sharee_table); |
1284 | + }, |
1285 | + |
1286 | + tearDown: function () { |
1287 | + Y.one('#fixture').empty(true); |
1288 | + delete window.LP; |
1289 | + }, |
1290 | + |
1291 | + _create_Widget: function(cfg) { |
1292 | + var ns = Y.lp.registry.sharing.sharingdetailsview; |
1293 | + return new ns.SharingDetailsView(cfg); |
1294 | + }, |
1295 | + |
1296 | + test_library_exists: function () { |
1297 | + Y.Assert.isObject(Y.lp.registry.sharing.sharingdetailsview, |
1298 | + "Could not locate the " + |
1299 | + "lp.registry.sharing.sharingdetailsview module"); |
1300 | + }, |
1301 | + |
1302 | + test_widget_can_be_instantiated: function() { |
1303 | + this.view = this._create_Widget(); |
1304 | + Y.Assert.isInstanceOf( |
1305 | + Y.lp.registry.sharing.sharingdetailsview.SharingDetailsView, |
1306 | + this.view, |
1307 | + "Sharing details view failed to be instantiated"); |
1308 | + }, |
1309 | + |
1310 | + // The view is correctly rendered. |
1311 | + test_render: function() { |
1312 | + this.view = this._create_Widget(); |
1313 | + this.view.render(); |
1314 | + // The sharing details table - we'll just check one row |
1315 | + Y.Assert.isNotNull( |
1316 | + Y.one('#sharing-table-body tr[id=shared-bug-2]')); |
1317 | + }, |
1318 | + |
1319 | + // Read only mode disables the correct things. |
1320 | + test_readonly: function() { |
1321 | + window.LP.cache.sharing_write_enabled = false; |
1322 | + this.view = this._create_Widget(); |
1323 | + this.view.render(); |
1324 | + Y.Assert.isFalse( |
1325 | + this.view.get('sharing_details_table') |
1326 | + .get('write_enabled')); |
1327 | + }, |
1328 | + |
1329 | + // Clicking a bug remove link calls the confirm_grant_removal |
1330 | + // method with the correct parameters. |
1331 | + test_remove_bug_grant_click: function() { |
1332 | + this.view = this._create_Widget(); |
1333 | + this.view.render(); |
1334 | + var confirmRemove_called = false; |
1335 | + this.view.confirm_grant_removal = function( |
1336 | + delete_link, artifact_uri, artifact_name, artifact_type) { |
1337 | + Y.Assert.areEqual('api/devel/bugs/2', artifact_uri); |
1338 | + Y.Assert.areEqual('Bug 2', artifact_name); |
1339 | + Y.Assert.areEqual('bug', artifact_type); |
1340 | + Y.Assert.areEqual(delete_link_to_click, delete_link); |
1341 | + confirmRemove_called = true; |
1342 | + |
1343 | + }; |
1344 | + var delete_link_to_click = |
1345 | + Y.one('#sharing-table-body span[id=remove-bug-2] a'); |
1346 | + delete_link_to_click.simulate('click'); |
1347 | + Y.Assert.isTrue(confirmRemove_called); |
1348 | + }, |
1349 | + |
1350 | + // Clicking a bug remove link calls the confirm_grant_removal |
1351 | + // method with the correct parameters. |
1352 | + test_remove_branch_grant_click: function() { |
1353 | + this.view = this._create_Widget(); |
1354 | + this.view.render(); |
1355 | + var confirmRemove_called = false; |
1356 | + this.view.confirm_grant_removal = function( |
1357 | + delete_link, artifact_uri, artifact_name, artifact_type) { |
1358 | + Y.Assert.areEqual( |
1359 | + 'api/devel/~someone/+junk/somebranch', artifact_uri); |
1360 | + Y.Assert.areEqual( |
1361 | + 'lp:~someone/+junk/somebranch', artifact_name); |
1362 | + Y.Assert.areEqual('branch', artifact_type); |
1363 | + Y.Assert.areEqual(delete_link_to_click, delete_link); |
1364 | + confirmRemove_called = true; |
1365 | + |
1366 | + }; |
1367 | + var delete_link_to_click = |
1368 | + Y.one('#sharing-table-body span[id=remove-branch-2] a'); |
1369 | + delete_link_to_click.simulate('click'); |
1370 | + Y.Assert.isTrue(confirmRemove_called); |
1371 | + }, |
1372 | + |
1373 | + //Test the behaviour of the removal confirmation dialog. |
1374 | + _test_confirm_grant_removal: function(click_ok) { |
1375 | + this.view = this._create_Widget(); |
1376 | + this.view.render(); |
1377 | + var performRemove_called = false; |
1378 | + this.view.perform_remove_grant = function( |
1379 | + delete_link, artifact_uri, artifact_type) { |
1380 | + Y.Assert.areEqual('api/devel/bugs/2', artifact_uri); |
1381 | + Y.Assert.areEqual('bug', artifact_type); |
1382 | + Y.Assert.areEqual(artifact_delete_link, delete_link); |
1383 | + performRemove_called = true; |
1384 | + |
1385 | + }; |
1386 | + var artifact_delete_link = |
1387 | + Y.one('#sharing-table-body td[id=remove-bug-2] a'); |
1388 | + this.view.confirm_grant_removal( |
1389 | + artifact_delete_link, 'api/devel/bugs/2', 'Bug 2', 'bug'); |
1390 | + var co = Y.one('.yui3-overlay.yui3-lp-app-confirmationoverlay'); |
1391 | + var actions = co.one('.yui3-lazr-formoverlay-actions'); |
1392 | + var btn_style; |
1393 | + if (click_ok) { |
1394 | + btn_style = '.ok-btn'; |
1395 | + } else { |
1396 | + btn_style = '.cancel-btn'; |
1397 | + } |
1398 | + var button = actions.one(btn_style); |
1399 | + button.simulate('click'); |
1400 | + Y.Assert.areEqual(click_ok, performRemove_called); |
1401 | + Y.Assert.isTrue( |
1402 | + co.hasClass('yui3-lp-app-confirmationoverlay-hidden')); |
1403 | + }, |
1404 | + |
1405 | + //Test the remove confirmation dialog when the user clicks Ok. |
1406 | + test_confirm_sharee_removal_ok: function() { |
1407 | + this._test_confirm_grant_removal(true); |
1408 | + }, |
1409 | + |
1410 | + //Test the remove confirmation dialog when the user clicks Cancel. |
1411 | + test_confirm_sharee_removal_cancel: function() { |
1412 | + this._test_confirm_grant_removal(false); |
1413 | + }, |
1414 | + |
1415 | + // The perform_remove_grant method makes the expected XHR calls when a |
1416 | + // bug grant remove link is clicked. |
1417 | + test_perform_remove_bug_grant: function() { |
1418 | + var mockio = new Y.lp.testing.mockio.MockIo(); |
1419 | + var lp_client = new Y.lp.client.Launchpad({ |
1420 | + io_provider: mockio |
1421 | + }); |
1422 | + this.view = this._create_Widget({ |
1423 | + lp_client: lp_client |
1424 | + }); |
1425 | + this.view.render(); |
1426 | + var remove_grant_success_called = false; |
1427 | + var self = this; |
1428 | + this.view.remove_grant_success = function(artifact_uri) { |
1429 | + Y.Assert.areEqual('api/devel/bugs/2', artifact_uri); |
1430 | + remove_grant_success_called = true; |
1431 | + }; |
1432 | + var delete_link = |
1433 | + Y.one('#sharing-table-body span[id=remove-bug-2] a'); |
1434 | + this.view.perform_remove_grant( |
1435 | + delete_link, 'api/devel/bugs/2', 'bug'); |
1436 | + Y.Assert.areEqual( |
1437 | + '/api/devel/+services/sharing', |
1438 | + mockio.last_request.url); |
1439 | + var expected_qs = ''; |
1440 | + expected_qs = Y.lp.client.append_qs( |
1441 | + expected_qs, 'ws.op', 'revokeAccessGrants'); |
1442 | + expected_qs = Y.lp.client.append_qs( |
1443 | + expected_qs, 'pillar', '/pillar'); |
1444 | + expected_qs = Y.lp.client.append_qs( |
1445 | + expected_qs, 'sharee', '~fred'); |
1446 | + expected_qs = Y.lp.client.append_qs( |
1447 | + expected_qs, 'bugs', 'api/devel/bugs/2'); |
1448 | + Y.Assert.areEqual(expected_qs, mockio.last_request.config.data); |
1449 | + mockio.last_request.successJSON({}); |
1450 | + Y.Assert.isTrue(remove_grant_success_called); |
1451 | + }, |
1452 | + |
1453 | + // The perform_remove_grant method makes the expected XHR calls when a |
1454 | + // branch grant remove link is clicked. |
1455 | + test_perform_remove_branch_grant: function() { |
1456 | + var mockio = new Y.lp.testing.mockio.MockIo(); |
1457 | + var lp_client = new Y.lp.client.Launchpad({ |
1458 | + io_provider: mockio |
1459 | + }); |
1460 | + this.view = this._create_Widget({ |
1461 | + lp_client: lp_client |
1462 | + }); |
1463 | + this.view.render(); |
1464 | + var remove_grant_success_called = false; |
1465 | + var self = this; |
1466 | + this.view.remove_grant_success = function(artifact_uri) { |
1467 | + Y.Assert.areEqual( |
1468 | + 'api/devel/~someone/+junk/somebranch', artifact_uri); |
1469 | + remove_grant_success_called = true; |
1470 | + }; |
1471 | + var delete_link = |
1472 | + Y.one('#sharing-table-body span[id=remove-branch-2] a'); |
1473 | + this.view.perform_remove_grant( |
1474 | + delete_link, 'api/devel/~someone/+junk/somebranch', 'branch'); |
1475 | + Y.Assert.areEqual( |
1476 | + '/api/devel/+services/sharing', |
1477 | + mockio.last_request.url); |
1478 | + var expected_qs = ''; |
1479 | + expected_qs = Y.lp.client.append_qs( |
1480 | + expected_qs, 'ws.op', 'revokeAccessGrants'); |
1481 | + expected_qs = Y.lp.client.append_qs( |
1482 | + expected_qs, 'pillar', '/pillar'); |
1483 | + expected_qs = Y.lp.client.append_qs( |
1484 | + expected_qs, 'sharee', '~fred'); |
1485 | + expected_qs = Y.lp.client.append_qs( |
1486 | + expected_qs, 'branches', 'api/devel/~someone/+junk/somebranch'); |
1487 | + Y.Assert.areEqual(expected_qs, mockio.last_request.config.data); |
1488 | + mockio.last_request.successJSON({}); |
1489 | + Y.Assert.isTrue(remove_grant_success_called); |
1490 | + }, |
1491 | + |
1492 | + // The remove bug grant callback updates the model and syncs the UI. |
1493 | + test_remove_bug_grant_success: function() { |
1494 | + this.view = this._create_Widget({anim_duration: 0}); |
1495 | + this.view.render(); |
1496 | + var syncUI_called = false; |
1497 | + this.view.syncUI = function() { |
1498 | + syncUI_called = true; |
1499 | + }; |
1500 | + this.view.remove_grant_success('api/devel/bugs/2'); |
1501 | + Y.Assert.isTrue(syncUI_called); |
1502 | + Y.Array.each(window.LP.cache.bugs, |
1503 | + function(bug) { |
1504 | + Y.Assert.areNotEqual(2, bug.bug_id); |
1505 | + }); |
1506 | + }, |
1507 | + |
1508 | + // The remove branch grant callback updates the model and syncs the UI. |
1509 | + test_remove_branch_grant_success: function() { |
1510 | + this.view = this._create_Widget({anim_duration: 0}); |
1511 | + this.view.render(); |
1512 | + var syncUI_called = false; |
1513 | + this.view.syncUI = function() { |
1514 | + syncUI_called = true; |
1515 | + }; |
1516 | + this.view.remove_grant_success( |
1517 | + 'api/devel/~someone/+junk/somebranch'); |
1518 | + Y.Assert.isTrue(syncUI_called); |
1519 | + Y.Array.each(window.LP.cache.branches, |
1520 | + function(branch) { |
1521 | + Y.Assert.areNotEqual(2, branch.branch_id); |
1522 | + }); |
1523 | + }, |
1524 | + |
1525 | + // Test that syncUI works as expected. |
1526 | + test_syncUI: function() { |
1527 | + this.view = this._create_Widget(); |
1528 | + this.view.render(); |
1529 | + var sharee_table = this.view.get('sharing_details_table'); |
1530 | + var table_syncUI_called = false; |
1531 | + sharee_table.syncUI = function() { |
1532 | + table_syncUI_called = true; |
1533 | + }; |
1534 | + this.view.syncUI(); |
1535 | + Y.Assert.isTrue(table_syncUI_called); |
1536 | + } |
1537 | + })); |
1538 | + |
1539 | +}, '0.1', {'requires': ['test', 'console', 'event', 'node-event-simulate', |
1540 | + 'lp.testing.mockio', |
1541 | + 'lp.registry.sharing.sharingdetails', |
1542 | + 'lp.registry.sharing.sharingdetailsview']}); |
1543 | |
1544 | === modified file 'lib/lp/registry/javascript/tests/test_team.js' |
1545 | --- lib/lp/registry/javascript/tests/test_team.js 2012-03-02 20:19:50 +0000 |
1546 | +++ lib/lp/registry/javascript/tests/test_team.js 2012-04-04 05:02:23 +0000 |
1547 | @@ -22,7 +22,7 @@ |
1548 | |
1549 | test_library_exists: function() { |
1550 | Y.Assert.isObject(Y.lp.registry.team, |
1551 | - "We should be able to locate the lp.registry.team module"); |
1552 | + "Could not locate the lp.registry.team module"); |
1553 | }, |
1554 | |
1555 | // The initialise_team_edit() method invokes the visibility_changed() |
1556 | |
1557 | === modified file 'lib/lp/registry/templates/pillar-sharing-details.pt' |
1558 | --- lib/lp/registry/templates/pillar-sharing-details.pt 2012-03-27 21:12:27 +0000 |
1559 | +++ lib/lp/registry/templates/pillar-sharing-details.pt 2012-04-04 05:02:23 +0000 |
1560 | @@ -10,17 +10,12 @@ |
1561 | <head> |
1562 | <metal:block fill-slot="head_epilogue"> |
1563 | <script> |
1564 | - LPJS.use('base', 'node', 'event', 'lp.registry.sharing.details', |
1565 | + LPJS.use('base', 'node', 'event', 'lp.registry.sharing.sharingdetailsview', |
1566 | function(Y) { |
1567 | Y.on('domready', function() { |
1568 | - var config = { |
1569 | - branches: LP.cache.branches, |
1570 | - bugs: LP.cache.bugs |
1571 | - }; |
1572 | - var details_module = Y.lp.registry.sharing.details; |
1573 | - var details_widget = new details_module.SharingDetailsTable( |
1574 | - config); |
1575 | - details_widget.render(); |
1576 | + var details_module = Y.lp.registry.sharing.sharingdetailsview; |
1577 | + var details_view = new details_module.SharingDetailsView(); |
1578 | + details_view.render(); |
1579 | }); |
1580 | }); |
1581 | </script> |
1582 | @@ -47,16 +42,12 @@ |
1583 | <col width="20px"/> |
1584 | <col width="auto"/> |
1585 | <col width="auto"/> |
1586 | - <col width="30%"/> |
1587 | <col width="auto"/> |
1588 | <thead> |
1589 | <tr> |
1590 | - <th colspan="3" width=""> |
1591 | + <th colspan="4" width=""> |
1592 | <a href="#" class="sortheader">Bug Report or Branch</a> |
1593 | </th> |
1594 | - <th colspan="2" width=""> |
1595 | - <a href="#" class="sortheader">Via</a> |
1596 | - </th> |
1597 | </tr> |
1598 | </thead> |
1599 | <tbody id="sharing-table-body"></tbody> |
1600 | |
1601 | === modified file 'standard_test_template.js' |
1602 | --- standard_test_template.js 2012-02-03 17:15:44 +0000 |
1603 | +++ standard_test_template.js 2012-04-04 05:02:23 +0000 |
1604 | @@ -13,7 +13,7 @@ |
1605 | |
1606 | test_library_exists: function () { |
1607 | Y.Assert.isObject(Y.lp.${LIBRARY}, |
1608 | - "We should be able to locate the lp.${LIBRARY} module"); |
1609 | + "Could not locate the lp.${LIBRARY} module"); |
1610 | } |
1611 | |
1612 | })); |
I see the SharingDetailsT able.initialize r lost its bugs and branches setters, yet the tests show everything works. What this unused data? I think the bugs and branches in the cache were the real data source, not the config.
Line 355 repeats the common mistake of creating a sprite without allocating space for it. Elements with sprites must contain content, add a nbsp; importance} }"> </span> ',
<span class="sprite bug-{{bug_
Line 529 has bogus markup "<br><br>" never use two <br />, because more than one means your markup and css is broken. Most browser strip all but the first one when rendering sibling blocks because they know css is the correct way to handle the situation. the <br /> must state it is empty as well. I can see the style attr is used with a class. This markup is just broken. I am certain it came from somewhere else in Lp.
This is a small semantic issue I share with Julian, "should" implies we are uncertain about how the code we wrote operates. "Should" on lines 729 and 999 adds a Heisenberg/ Wittgenstein state of uncertainty, when I am very certain the module "must" be loaded for the test to complete. Maybe
"Could not locate the "