Merge lp:~wallyworld/launchpad/sharing-details-delete-966641 into lp:launchpad

Proposed by Ian Booth
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
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 PillarPersonSharingView was enhanced to place additional required data in the json request cache for the view.

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_sharingdetailsview was added for the new yui sharing details view class.

On the server side of things, the PillarSharingDetails tests were enhanced to better check the view data model and test for new things added to the model.

bin/test -vvct test_pillar_sharing -t test_sharingdetailsview -t test_sharingdetails

== Lint ==

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/registry/browser/pillar.py
  lib/lp/registry/browser/tests/test_pillar_sharing.py
  lib/lp/registry/javascript/sharing/sharingdetails.js
  lib/lp/registry/javascript/sharing/sharingdetailsview.js
  lib/lp/registry/javascript/sharing/tests/test_sharingdetails.html
  lib/lp/registry/javascript/sharing/tests/test_sharingdetails.js
  lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.html
  lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js
  lib/lp/registry/templates/pillar-sharing-details.pt

To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

I see the SharingDetailsTable.initializer 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;
    <span class="sprite bug-{{bug_importance}}">&nbsp;</span>',

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 "

review: Approve (code)
Revision history for this message
Ian Booth (wallyworld) wrote :

Thanks for the review.

On 04/04/12 01:58, Curtis Hovey wrote:
> Review: Approve code
>
> I see the SharingDetailsTable.initializer 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.
>

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_importance}}">&nbsp;</span>',
>

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/Wittgenstein state of uncertainty, when I am very certain the module "must" be loaded for the test to complete. Maybe
> "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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/app/javascript/activator/tests/test_activator.js'
--- lib/lp/app/javascript/activator/tests/test_activator.js 2012-02-03 19:12:02 +0000
+++ lib/lp/app/javascript/activator/tests/test_activator.js 2012-04-04 05:02:23 +0000
@@ -69,7 +69,7 @@
6969
70 test_library_exists: function () {70 test_library_exists: function () {
71 Y.Assert.isObject(Y.lazr.activator,71 Y.Assert.isObject(Y.lazr.activator,
72 "We should be able to locate the lazr.activator module");72 "Could not locate the lazr.activator module");
73 },73 },
7474
75 test_correct_animation_node: function() {75 test_correct_animation_node: function() {
7676
=== modified file 'lib/lp/app/javascript/autocomplete/tests/test_autocomplete.js'
--- lib/lp/app/javascript/autocomplete/tests/test_autocomplete.js 2012-02-03 17:57:36 +0000
+++ lib/lp/app/javascript/autocomplete/tests/test_autocomplete.js 2012-04-04 05:02:23 +0000
@@ -49,7 +49,7 @@
4949
50 test_library_exists: function () {50 test_library_exists: function () {
51 Y.Assert.isObject(Y.lazr.AutoComplete,51 Y.Assert.isObject(Y.lazr.AutoComplete,
52 "We should be able to locate the lazr.autocomplete module");52 "Could not locate the lazr.autocomplete module");
53 },53 },
5454
55 test_widget_starts_hidden: function() {55 test_widget_starts_hidden: function() {
5656
=== modified file 'lib/lp/app/javascript/choiceedit/tests/test_choiceedit.js'
--- lib/lp/app/javascript/choiceedit/tests/test_choiceedit.js 2012-02-17 01:47:49 +0000
+++ lib/lp/app/javascript/choiceedit/tests/test_choiceedit.js 2012-04-04 05:02:23 +0000
@@ -64,7 +64,7 @@
6464
65 test_library_exists: function () {65 test_library_exists: function () {
66 Y.Assert.isObject(Y.ChoiceSource,66 Y.Assert.isObject(Y.ChoiceSource,
67 "We should be able to locate the lazr.choiceedit " +67 "Could not locate the lazr.choiceedit " +
68 "module");68 "module");
69 },69 },
7070
7171
=== modified file 'lib/lp/app/javascript/confirmationoverlay/tests/test_confirmationoverlay.js'
--- lib/lp/app/javascript/confirmationoverlay/tests/test_confirmationoverlay.js 2012-02-03 20:37:06 +0000
+++ lib/lp/app/javascript/confirmationoverlay/tests/test_confirmationoverlay.js 2012-04-04 05:02:23 +0000
@@ -25,7 +25,7 @@
2525
26 test_library_exists: function () {26 test_library_exists: function () {
27 Y.Assert.isObject(Y.lp.app.confirmationoverlay,27 Y.Assert.isObject(Y.lp.app.confirmationoverlay,
28 "We should be able to locate the lp.app.confirmationoverlay module");28 "Could not locate the lp.app.confirmationoverlay module");
29 },29 },
3030
31 test_button_set: function() {31 test_button_set: function() {
3232
=== modified file 'lib/lp/app/javascript/formoverlay/tests/test_formoverlay.js'
--- lib/lp/app/javascript/formoverlay/tests/test_formoverlay.js 2012-02-06 13:30:53 +0000
+++ lib/lp/app/javascript/formoverlay/tests/test_formoverlay.js 2012-04-04 05:02:23 +0000
@@ -62,7 +62,7 @@
6262
63 test_library_exists: function () {63 test_library_exists: function () {
64 Y.Assert.isObject(Y.lazr.FormOverlay,64 Y.Assert.isObject(Y.lazr.FormOverlay,
65 "We should be able to locate the lp.lazr.FormOverlay module");65 "Could not locate the lp.lazr.FormOverlay module");
66 },66 },
6767
68 test_form_overlay_can_be_instantiated: function() {68 test_form_overlay_can_be_instantiated: function() {
6969
=== modified file 'lib/lp/app/javascript/formwidgets/tests/test_resizing_textarea.js'
--- lib/lp/app/javascript/formwidgets/tests/test_resizing_textarea.js 2012-02-06 13:32:56 +0000
+++ lib/lp/app/javascript/formwidgets/tests/test_resizing_textarea.js 2012-04-04 05:02:23 +0000
@@ -54,7 +54,7 @@
5454
55 test_library_exists: function () {55 test_library_exists: function () {
56 Y.Assert.isObject(Y.lp.app.formwidgets.ResizingTextarea,56 Y.Assert.isObject(Y.lp.app.formwidgets.ResizingTextarea,
57 "We should be able to locate the " +57 "Could not locate the " +
58 "lp.app.formwidgets.ResizingTextarea module");58 "lp.app.formwidgets.ResizingTextarea module");
59 },59 },
6060
6161
=== modified file 'lib/lp/app/javascript/inlineedit/tests/test_inline_edit.js'
--- lib/lp/app/javascript/inlineedit/tests/test_inline_edit.js 2012-03-01 20:35:55 +0000
+++ lib/lp/app/javascript/inlineedit/tests/test_inline_edit.js 2012-04-04 05:02:23 +0000
@@ -106,7 +106,7 @@
106 },106 },
107 test_library_exists: function () {107 test_library_exists: function () {
108 Y.Assert.isObject(Y.InlineEditor,108 Y.Assert.isObject(Y.InlineEditor,
109 "We should be able to locate the lp.${LIBRARY} module");109 "Could not locate the lp.${LIBRARY} module");
110 },110 },
111111
112 test_input_value_set_during_sync: function() {112 test_input_value_set_during_sync: function() {
113113
=== modified file 'lib/lp/app/javascript/overlay/tests/test_overlay.js'
--- lib/lp/app/javascript/overlay/tests/test_overlay.js 2012-02-06 18:01:41 +0000
+++ lib/lp/app/javascript/overlay/tests/test_overlay.js 2012-04-04 05:02:23 +0000
@@ -48,7 +48,7 @@
4848
49 test_library_exists: function () {49 test_library_exists: function () {
50 Y.Assert.isObject(Y.lazr.PrettyOverlay,50 Y.Assert.isObject(Y.lazr.PrettyOverlay,
51 "We should be able to locate the lazr.PrettyOverlay module");51 "Could not locate the lazr.PrettyOverlay module");
52 },52 },
5353
54 hitEscape: function() {54 hitEscape: function() {
5555
=== modified file 'lib/lp/app/javascript/picker/tests/test_picker.js'
--- lib/lp/app/javascript/picker/tests/test_picker.js 2012-02-06 18:40:00 +0000
+++ lib/lp/app/javascript/picker/tests/test_picker.js 2012-04-04 05:02:23 +0000
@@ -44,7 +44,7 @@
4444
45 test_library_exists: function () {45 test_library_exists: function () {
46 Y.Assert.isObject(Y.lazr.picker,46 Y.Assert.isObject(Y.lazr.picker,
47 "We should be able to locate the lazr.picker module");47 "Could not locate the lazr.picker module");
48 },48 },
4949
50 test_picker_can_be_instantiated: function() {50 test_picker_can_be_instantiated: function() {
5151
=== modified file 'lib/lp/app/javascript/picker/tests/test_picker_patcher.js'
--- lib/lp/app/javascript/picker/tests/test_picker_patcher.js 2012-02-07 15:56:53 +0000
+++ lib/lp/app/javascript/picker/tests/test_picker_patcher.js 2012-04-04 05:02:23 +0000
@@ -66,7 +66,7 @@
6666
67 test_library_exists: function () {67 test_library_exists: function () {
68 Y.Assert.isObject(Y.lp.app.picker,68 Y.Assert.isObject(Y.lp.app.picker,
69 "We should be able to locate the lp.app.picker module");69 "Could not locate the lp.app.picker module");
70 },70 },
7171
72 create_picker: function(validate_callback, extra_config) {72 create_picker: function(validate_callback, extra_config) {
7373
=== modified file 'lib/lp/app/javascript/subscribers/tests/test_subscribers_list.js'
--- lib/lp/app/javascript/subscribers/tests/test_subscribers_list.js 2012-02-07 19:48:00 +0000
+++ lib/lp/app/javascript/subscribers/tests/test_subscribers_list.js 2012-04-04 05:02:23 +0000
@@ -103,7 +103,7 @@
103103
104 test_library_exists: function () {104 test_library_exists: function () {
105 Y.Assert.isObject(Y.lp.app.subscribers.subscribers_list,105 Y.Assert.isObject(Y.lp.app.subscribers.subscribers_list,
106 "We should be able to locate the " +106 "Could not locate the " +
107 "lp.app.subscribers.subscribers_list module");107 "lp.app.subscribers.subscribers_list module");
108 },108 },
109 test_no_container_error: function() {109 test_no_container_error: function() {
110110
=== modified file 'lib/lp/app/javascript/testing/tests/test_mockio.js'
--- lib/lp/app/javascript/testing/tests/test_mockio.js 2012-02-10 15:58:36 +0000
+++ lib/lp/app/javascript/testing/tests/test_mockio.js 2012-04-04 05:02:23 +0000
@@ -45,7 +45,7 @@
4545
46 test_library_exists: function () {46 test_library_exists: function () {
47 Y.Assert.isObject(Y.lp.testing.mockio,47 Y.Assert.isObject(Y.lp.testing.mockio,
48 "We should be able to locate the lp.testing.mockio module");48 "Could not locate the lp.testing.mockio module");
49 },49 },
5050
51 test_respond_success: function() {51 test_respond_success: function() {
5252
=== modified file 'lib/lp/app/javascript/tests/test_ajax_batch_navigator.js'
--- lib/lp/app/javascript/tests/test_ajax_batch_navigator.js 2012-02-07 20:11:18 +0000
+++ lib/lp/app/javascript/tests/test_ajax_batch_navigator.js 2012-04-04 05:02:23 +0000
@@ -101,7 +101,7 @@
101101
102 test_library_exists: function () {102 test_library_exists: function () {
103 Y.Assert.isObject(Y.lp.app.batchnavigator,103 Y.Assert.isObject(Y.lp.app.batchnavigator,
104 "We should be able to locate the lp.app.batchnavigator");104 "Could not locate the lp.app.batchnavigator");
105 },105 },
106106
107 test_navigator_construction: function() {107 test_navigator_construction: function() {
108108
=== modified file 'lib/lp/app/javascript/tests/test_ajax_log.js'
--- lib/lp/app/javascript/tests/test_ajax_log.js 2012-02-15 12:45:13 +0000
+++ lib/lp/app/javascript/tests/test_ajax_log.js 2012-04-04 05:02:23 +0000
@@ -10,7 +10,7 @@
1010
11 test_library_exists: function () {11 test_library_exists: function () {
12 Y.Assert.isObject(Y.lp.ajax_log,12 Y.Assert.isObject(Y.lp.ajax_log,
13 "We should be able to locate the lp.ajax_log module");13 "Could not locate the lp.ajax_log module");
14 }14 }
1515
16 }));16 }));
1717
=== modified file 'lib/lp/app/javascript/tests/test_beta_notification.js'
--- lib/lp/app/javascript/tests/test_beta_notification.js 2012-02-07 20:20:59 +0000
+++ lib/lp/app/javascript/tests/test_beta_notification.js 2012-04-04 05:02:23 +0000
@@ -39,7 +39,7 @@
3939
40 test_library_exists: function () {40 test_library_exists: function () {
41 Y.Assert.isObject(Y.lp.app.beta_features,41 Y.Assert.isObject(Y.lp.app.beta_features,
42 "We should be able to locate the lp.app.beta_features module");42 "Could not locate the lp.app.beta_features module");
43 },43 },
4444
45 test_beta_banner_one_beta_feature: function() {45 test_beta_banner_one_beta_feature: function() {
4646
=== modified file 'lib/lp/bugs/javascript/bugtask_index.js'
--- lib/lp/bugs/javascript/bugtask_index.js 2012-03-21 01:26:18 +0000
+++ lib/lp/bugs/javascript/bugtask_index.js 2012-04-04 05:02:23 +0000
@@ -742,7 +742,8 @@
742 var delete_text_template = [742 var delete_text_template = [
743 '<p class="large-warning" style="padding:2px 2px 0 36px;">',743 '<p class="large-warning" style="padding:2px 2px 0 36px;">',
744 ' You are about to mark bug "{bug}"<br>as no longer affecting',744 ' You are about to mark bug "{bug}"<br>as no longer affecting',
745 ' {target}.<br><br>',745 ' {target}.',
746 '</p><p>',
746 ' <strong>Please confirm you really want to do this.</strong>',747 ' <strong>Please confirm you really want to do this.</strong>',
747 '</p>'748 '</p>'
748 ].join('');749 ].join('');
749750
=== modified file 'lib/lp/registry/browser/pillar.py'
--- lib/lp/registry/browser/pillar.py 2012-03-31 11:32:15 +0000
+++ lib/lp/registry/browser/pillar.py 2012-04-04 05:02:23 +0000
@@ -17,6 +17,7 @@
1717
18from lazr.restful import ResourceJSONEncoder18from lazr.restful import ResourceJSONEncoder
19from lazr.restful.interfaces import IJSONRequestCache19from lazr.restful.interfaces import IJSONRequestCache
20from lazr.restful.utils import get_current_web_service_request
20import simplejson21import simplejson
21from zope.component import getUtility22from zope.component import getUtility
22from zope.interface import (23from zope.interface import (
@@ -26,6 +27,7 @@
26from zope.schema.interfaces import IVocabulary27from zope.schema.interfaces import IVocabulary
27from zope.schema.vocabulary import getVocabularyRegistry28from zope.schema.vocabulary import getVocabularyRegistry
28from zope.security.interfaces import Unauthorized29from zope.security.interfaces import Unauthorized
30from zope.traversing.browser.absoluteurl import absoluteURL
2931
30from lp.app.browser.launchpad import iter_view_registrations32from lp.app.browser.launchpad import iter_view_registrations
31from lp.app.browser.tales import MenuAPI33from lp.app.browser.tales import MenuAPI
@@ -376,10 +378,25 @@
376 self._loadSharedArtifacts()378 self._loadSharedArtifacts()
377379
378 cache = IJSONRequestCache(self.request)380 cache = IJSONRequestCache(self.request)
379 branch_data = self._build_branch_template_data(self.branches)381 request = get_current_web_service_request()
380 bug_data = self._build_bug_template_data(self.bugs)382 branch_data = self._build_branch_template_data(self.branches, request)
383 bug_data = self._build_bug_template_data(self.bugs, request)
384 sharee_data = {
385 'displayname': self.person.displayname,
386 'self_link': absoluteURL(self.person, request)
387 }
388 pillar_data = {
389 'self_link': absoluteURL(self.pillar, request)
390 }
391 cache.objects['sharee'] = sharee_data
392 cache.objects['pillar'] = pillar_data
381 cache.objects['bugs'] = bug_data393 cache.objects['bugs'] = bug_data
382 cache.objects['branches'] = branch_data394 cache.objects['branches'] = branch_data
395 enabled_writable_flag = (
396 'disclosure.enhanced_sharing.writable')
397 write_flag_enabled = bool(getFeatureFlag(enabled_writable_flag))
398 cache.objects['sharing_write_enabled'] = (write_flag_enabled
399 and check_permission('launchpad.Edit', self.pillar))
383400
384 def _loadSharedArtifacts(self):401 def _loadSharedArtifacts(self):
385 bugs = []402 bugs = []
@@ -397,31 +414,35 @@
397 self.shared_bugs_count = len(bugs)414 self.shared_bugs_count = len(bugs)
398 self.shared_branches_count = len(branches)415 self.shared_branches_count = len(branches)
399416
400 def _build_branch_template_data(self, branches):417 def _build_branch_template_data(self, branches, request):
401 branch_data = []418 branch_data = []
402 for branch in branches:419 for branch in branches:
403 branch_data.append(dict(420 branch_data.append(dict(
404 branch_link=canonical_url(branch),421 self_link=absoluteURL(branch, request),
422 web_link=canonical_url(branch, path_only_if_possible=True),
405 branch_name=branch.unique_name,423 branch_name=branch.unique_name,
406 branch_id=branch.id))424 branch_id=branch.id))
407 return branch_data425 return branch_data
408426
409 def _build_bug_template_data(self, bugs):427 def _build_bug_template_data(self, bugs, request):
410 bug_data = []428 bug_data = []
411 for bug in bugs:429 for bug in bugs:
412 [bugtask] = [task for task in bug.bugtasks if430 [bugtask] = [task for task in bug.bugtasks if
413 task.target == self.pillar]431 task.target == self.pillar]
414 if bugtask is not None:432 if bugtask is not None:
415 url = canonical_url(bugtask, path_only_if_possible=True)433 web_link = canonical_url(bugtask, path_only_if_possible=True)
434 self_link = absoluteURL(bugtask, request)
416 importance = bugtask.importance.title.lower()435 importance = bugtask.importance.title.lower()
417 else:436 else:
418 # This shouldn't ever happen, but if it does there's no reason437 # This shouldn't ever happen, but if it does there's no reason
419 # to crash.438 # to crash.
420 url = canonical_url(bug, path_only_if_possible=True)439 web_link = canonical_url(bug, path_only_if_possible=True)
440 self_link = absoluteURL(bug, request)
421 importance = bug.default_bugtask.importance.title.lower()441 importance = bug.default_bugtask.importance.title.lower()
422442
423 bug_data.append(dict(443 bug_data.append(dict(
424 bug_link=url,444 self_link=self_link,
445 web_link=web_link,
425 bug_summary=bug.title,446 bug_summary=bug.title,
426 bug_id=bug.id,447 bug_id=bug.id,
427 bug_importance=importance))448 bug_importance=importance))
428449
=== modified file 'lib/lp/registry/browser/tests/test_pillar_sharing.py'
--- lib/lp/registry/browser/tests/test_pillar_sharing.py 2012-03-31 11:32:15 +0000
+++ lib/lp/registry/browser/tests/test_pillar_sharing.py 2012-04-04 05:02:23 +0000
@@ -7,6 +7,7 @@
77
8from BeautifulSoup import BeautifulSoup8from BeautifulSoup import BeautifulSoup
9from lazr.restful.interfaces import IJSONRequestCache9from lazr.restful.interfaces import IJSONRequestCache
10from lazr.restful.utils import get_current_web_service_request
10import simplejson11import simplejson
11from testtools.matchers import (12from testtools.matchers import (
12 LessThan,13 LessThan,
@@ -17,6 +18,7 @@
17from zope.component import getUtility18from zope.component import getUtility
18from zope.publisher.interfaces import NotFound19from zope.publisher.interfaces import NotFound
19from zope.security.interfaces import Unauthorized20from zope.security.interfaces import Unauthorized
21from zope.traversing.browser.absoluteurl import absoluteURL
2022
21from lp.app.interfaces.services import IService23from lp.app.interfaces.services import IService
22from lp.registry.enums import InformationType24from lp.registry.enums import InformationType
@@ -41,6 +43,9 @@
4143
4244
43DETAILS_ENABLED_FLAG = {'disclosure.enhanced_sharing_details.enabled': 'true'}45DETAILS_ENABLED_FLAG = {'disclosure.enhanced_sharing_details.enabled': 'true'}
46DETAILS_WRITE_FLAG = {
47 'disclosure.enhanced_sharing_details.enabled': 'true',
48 'disclosure.enhanced_sharing.writable': 'true'}
44ENABLED_FLAG = {'disclosure.enhanced_sharing.enabled': 'true'}49ENABLED_FLAG = {'disclosure.enhanced_sharing.enabled': 'true'}
45WRITE_FLAG = {'disclosure.enhanced_sharing.writable': 'true'}50WRITE_FLAG = {'disclosure.enhanced_sharing.writable': 'true'}
4651
@@ -55,21 +60,34 @@
55 person = self.factory.makePerson()60 person = self.factory.makePerson()
56 if with_sharing:61 if with_sharing:
57 if self.pillar_type == 'product':62 if self.pillar_type == 'product':
58 bug = self.factory.makeBug(63 self.bug = self.factory.makeBug(
64 product=self.pillar,
65 owner=self.pillar.owner,
66 private=True)
67 self.branch = self.factory.makeBranch(
59 product=self.pillar,68 product=self.pillar,
60 owner=self.pillar.owner,69 owner=self.pillar.owner,
61 private=True)70 private=True)
62 elif self.pillar_type == 'distribution':71 elif self.pillar_type == 'distribution':
63 bug = self.factory.makeBug(72 self.branch = None
73 self.bug = self.factory.makeBug(
64 distribution=self.pillar,74 distribution=self.pillar,
65 owner=self.pillar.owner,75 owner=self.pillar.owner,
66 private=True)76 private=True)
67 artifact = self.factory.makeAccessArtifact(concrete=bug)77 artifact = self.factory.makeAccessArtifact(concrete=self.bug)
68 policy = self.factory.makeAccessPolicy(pillar=self.pillar)78 policy = self.factory.makeAccessPolicy(pillar=self.pillar)
69 self.factory.makeAccessPolicyArtifact(79 self.factory.makeAccessPolicyArtifact(
70 artifact=artifact, policy=policy)80 artifact=artifact, policy=policy)
71 self.factory.makeAccessArtifactGrant(81 self.factory.makeAccessArtifactGrant(
72 artifact=artifact, grantee=person, grantor=self.pillar.owner)82 artifact=artifact, grantee=person, grantor=self.pillar.owner)
83 if self.branch:
84 artifact = self.factory.makeAccessArtifact(
85 concrete=self.branch)
86 self.factory.makeAccessPolicyArtifact(
87 artifact=artifact, policy=policy)
88 self.factory.makeAccessArtifactGrant(
89 artifact=artifact, grantee=person,
90 grantor=self.pillar.owner)
7391
74 return PillarPerson(self.pillar, person)92 return PillarPerson(self.pillar, person)
7593
@@ -110,6 +128,54 @@
110 view = create_initialized_view(pillarperson, '+index')128 view = create_initialized_view(pillarperson, '+index')
111 self.assertEqual(pillarperson.person.displayname, view.page_title)129 self.assertEqual(pillarperson.person.displayname, view.page_title)
112130
131 def test_view_data_model(self):
132 # Test that the json request cache contains the view data model.
133 with FeatureFixture(DETAILS_ENABLED_FLAG):
134 pillarperson = self.getPillarPerson()
135 view = create_initialized_view(pillarperson, '+index')
136 cache = IJSONRequestCache(view.request)
137 request = get_current_web_service_request()
138 self.assertEqual({
139 'self_link': absoluteURL(pillarperson.person, request),
140 'displayname': pillarperson.person.displayname
141 }, cache.objects.get('sharee'))
142 self.assertEqual({
143 'self_link': absoluteURL(pillarperson.pillar, request),
144 }, cache.objects.get('pillar'))
145 bugtask = self.bug.default_bugtask
146 self.assertEqual({
147 'bug_id': self.bug.id,
148 'bug_summary': self.bug.title,
149 'bug_importance': bugtask.importance.title.lower(),
150 'web_link': canonical_url(
151 bugtask, path_only_if_possible=True),
152 'self_link': absoluteURL(bugtask, request),
153 }, cache.objects.get('bugs')[0])
154 if self.pillar_type == 'product':
155 self.assertEqual({
156 'branch_id': self.branch.id,
157 'branch_name': self.branch.unique_name,
158 'web_link': canonical_url(
159 self.branch, path_only_if_possible=True),
160 'self_link': absoluteURL(self.branch, request),
161 }, cache.objects.get('branches')[0])
162
163 def test_view_write_enabled_without_feature_flag(self):
164 # Test that sharing_write_enabled is not set without the feature flag.
165 with FeatureFixture(DETAILS_ENABLED_FLAG):
166 pillarperson = self.getPillarPerson()
167 view = create_initialized_view(pillarperson, '+index')
168 cache = IJSONRequestCache(view.request)
169 self.assertFalse(cache.objects.get('sharing_write_enabled'))
170
171 def test_view_write_enabled_with_feature_flag(self):
172 # Test that sharing_write_enabled is set when required.
173 with FeatureFixture(DETAILS_WRITE_FLAG):
174 pillarperson = self.getPillarPerson()
175 view = create_initialized_view(pillarperson, '+index')
176 cache = IJSONRequestCache(view.request)
177 self.assertTrue(cache.objects.get('sharing_write_enabled'))
178
113179
114class TestProductSharingDetailsView(180class TestProductSharingDetailsView(
115 TestCaseWithFactory, PillarSharingDetailsMixin):181 TestCaseWithFactory, PillarSharingDetailsMixin):
116182
=== modified file 'lib/lp/registry/javascript/sharing/pillarsharingview.js'
--- lib/lp/registry/javascript/sharing/pillarsharingview.js 2012-03-31 11:32:15 +0000
+++ lib/lp/registry/javascript/sharing/pillarsharingview.js 2012-04-04 05:02:23 +0000
@@ -182,9 +182,9 @@
182 */182 */
183 confirm_sharee_removal: function(delete_link, person_uri, person_name) {183 confirm_sharee_removal: function(delete_link, person_uri, person_name) {
184 var confirm_text_template = [184 var confirm_text_template = [
185 '<p class="large-warning" style="padding:2px 2px 0 36px;">',185 '<p class="large-warning" style="padding:2px 2px 15px 36px;">',
186 ' Do you really want to stop sharing',186 ' Do you really want to stop sharing',
187 ' "{pillar}" with {person_name}?<br><br>',187 ' "{pillar}" with {person_name}?',
188 '</p>'188 '</p>'
189 ].join('');189 ].join('');
190 var confirm_text = Y.Lang.sub(confirm_text_template,190 var confirm_text = Y.Lang.sub(confirm_text_template,
191191
=== modified file 'lib/lp/registry/javascript/sharing/sharingdetails.js'
--- lib/lp/registry/javascript/sharing/sharingdetails.js 2012-03-28 22:21:37 +0000
+++ lib/lp/registry/javascript/sharing/sharingdetails.js 2012-04-04 05:02:23 +0000
@@ -3,12 +3,18 @@
3 *3 *
4 * Sharing details widget4 * Sharing details widget
5 *5 *
6 * @module lp.registry.sharing.details6 * @module lp.registry.sharing.sharingdetails
7 */7 */
88
9YUI.add('lp.registry.sharing.details', function(Y) {9YUI.add('lp.registry.sharing.sharingdetails', function(Y) {
1010
11var namespace = Y.namespace('lp.registry.sharing.details');11var namespace = Y.namespace('lp.registry.sharing.sharingdetails');
12
13var
14 NAME = "sharingDetailsTable",
15 // Events
16 REMOVE_GRANT = 'removeGrant';
17
12/*18/*
13 * Sharing details table widget.19 * Sharing details table widget.
14 * This widget displays the details of a specific person's shared artifacts.20 * This widget displays the details of a specific person's shared artifacts.
@@ -18,7 +24,12 @@
18}24}
1925
20SharingDetailsTable.ATTRS = {26SharingDetailsTable.ATTRS = {
2127 // The node holding the details table.
28 details_table_body: {
29 getter: function() {
30 return Y.one('#sharing-table-body');
31 }
32 },
22 table_body_template: {33 table_body_template: {
23 value: null34 value: null
24 },35 },
@@ -37,20 +48,20 @@
3748
38 branches: {49 branches: {
39 value: []50 value: []
51 },
52
53 write_enabled: {
54 value: false
55 },
56
57 person_name: {
58 value: null
40 }59 }
41};60};
4261
43Y.extend(SharingDetailsTable, Y.Widget, {62Y.extend(SharingDetailsTable, Y.Widget, {
4463
45 initializer: function(config) {64 initializer: function(config) {
46 if (Y.Lang.isValue(config.branches)) {
47 this.set('branches', config.branches);
48 }
49
50 if (Y.Lang.isValue(config.bugs)) {
51 this.set('bugs', config.bugs);
52 }
53
54 this.set(65 this.set(
55 'bug_details_row_template',66 'bug_details_row_template',
56 this._bug_details_row_template());67 this._bug_details_row_template());
@@ -62,6 +73,7 @@
62 this.set(73 this.set(
63 'table_body_template',74 'table_body_template',
64 this._table_body_template());75 this._table_body_template());
76 this.publish(REMOVE_GRANT);
65 },77 },
6678
67 renderUI: function() {79 renderUI: function() {
@@ -74,37 +86,75 @@
74 var template = this.get('table_body_template');86 var template = this.get('table_body_template');
75 var html = Y.lp.mustache.to_html(87 var html = Y.lp.mustache.to_html(
76 template,88 template,
77 {branches: branch_data, bugs: bug_data},89 {branches: branch_data, bugs: bug_data,
90 displayname: this.get('person_name')},
78 partials);91 partials);
79 var table = Y.one('#sharing-table-body');92
80 table.set('innerHTML', html);93 var details_table_body = this.get('details_table_body');
81 },94 var table_body_node = Y.Node.create(html);
95 details_table_body.replace(table_body_node);
96 this._update_editable_status();
97 },
98
99 _update_editable_status: function() {
100 var details_table_body = this.get('details_table_body');
101 if (!this.get('write_enabled')) {
102 details_table_body.all('.sprite.remove').each(function(node) {
103 node.addClass('unseen');
104 });
105 }
106 },
107
108 bindUI: function() {
109 // Bind the delete links.
110 if (!this.get('write_enabled')) {
111 return;
112 }
113 var details_table_body = this.get('details_table_body');
114 var self = this;
115 details_table_body.delegate('click', function(e) {
116 e.halt();
117 var delete_link = e.currentTarget;
118 var artifact_uri = delete_link.getAttribute('data-self_link');
119 var artifact_name = delete_link.getAttribute('data-name');
120 var artifact_type = delete_link.getAttribute('data-type');
121 self.fire(
122 REMOVE_GRANT, delete_link, artifact_uri, artifact_name,
123 artifact_type);
124 }, 'span[id^=remove-] a');
125 },
82126
83 _table_body_template: function() {127 _table_body_template: function() {
84 return [128 return [
129 '<tbody id="sharing-table-body">',
85 '{{#branches}}',130 '{{#branches}}',
86 '{{> branch}}',131 '{{> branch}}',
87 '{{/branches}}',132 '{{/branches}}',
88 '{{#bugs}}',133 '{{#bugs}}',
89 '{{> bug}}',134 '{{> bug}}',
90 '{{/bugs}}'135 '{{/bugs}}',
136 '</tbody>'
91 ].join(' ');137 ].join(' ');
92 },138 },
93139
94 _bug_details_row_template: function() {140 _bug_details_row_template: function() {
95 return [141 return [
96 '<tr>',142 '<tr id="shared-bug-{{ bug_id }}">',
97 ' <td class="icon right">',143 ' <td class="icon right">',
98 ' <span class="sprite bug-{{ bug_importance }}"></span>',144 ' <span class="sprite bug-{{bug_importance}}">&nbsp;</span>',
99 ' </td>',145 ' </td>',
100 ' <td class="amount">{{ bug_id }}</td>',146 ' <td class="amount">{{bug_id}}</td>',
101 ' <td>',147 ' <td>',
102 ' <a href="{{ bug_link }}">{{ bug_summary }}</a>',148 ' <a href="{{web_link}}">{{bug_summary}}</a>',
103 ' </td>',149 ' </td>',
104 ' <td>&mdash;</td>',150 ' <td class="action-icons nowrap">',
105 ' <td class="actions" id="remove-bug-{{ bug_id }}">',151 ' <span id="remove-bug-{{ bug_id }}">',
106 ' <a class="sprite remove" href="#"',152 ' <a class="sprite remove" href="#"',
107 ' title="Unshare this with the user">&nbsp;</a>',153 ' title="Unshare bug {{bug_id}} with {{displayname}}"',
154 ' data-self_link="{{self_link}}" data-name="Bug {{bug_id}}"',
155 ' data-type="bug">',
156 ' &nbsp;</a>',
157 ' </span>',
108 ' </td>',158 ' </td>',
109 '</tr>'159 '</tr>'
110 ].join(' ');160 ].join(' ');
@@ -112,27 +162,31 @@
112162
113 _branch_details_row_template: function() {163 _branch_details_row_template: function() {
114 return [164 return [
115 '<tr>',165 '<tr id="shared-branch-{{ branch_id }}">',
116 ' <td colspan="3">',166 ' <td colspan="3">',
117 ' <a class="sprite branch" href="{{ branch_link }}">',167 ' <a class="sprite branch" href="{{web_link}}">',
118 ' {{ branch_name }}',168 ' {{branch_name}}',
119 ' </a>',169 ' </a>',
120 ' </td>',170 ' </td>',
121 ' <td>&mdash;</td>',171 ' <td class="action-icons nowrap">',
122 ' <td class="actions" id="remove-branch-{{ branch_id }}">',172 ' <span id="remove-branch-{{branch_id}}">',
123 ' <a class="sprite remove" href="#"',173 ' <a class="sprite remove" href="#"',
124 ' title="Unshare this with the user">&nbsp;</a>',174 ' title="Unshare branch {{branch_name}} with {{displayname}}"',
175 ' data-self_link="{{self_link}}" data-name="{{branch_name}}"',
176 ' data-type="branch">',
177 ' &nbsp;</a>',
178 ' </span>',
125 ' </td>',179 ' </td>',
126 '</tr>'180 '</tr>'
127 ].join(' ');181 ].join(' ');
128 }182 }
129});183});
130184
131SharingDetailsTable.NAME = 'sharingDetailsTable';185SharingDetailsTable.NAME = NAME;
186SharingDetailsTable.REMOVE_GRANT = REMOVE_GRANT;
132187
133namespace.SharingDetailsTable = SharingDetailsTable;188namespace.SharingDetailsTable = SharingDetailsTable;
134189
135}, "0.1", { "requires": [190}, "0.1", { "requires": [
136 'node',191 'node', 'event', 'lp.mustache'
137 'lp.mustache'
138] });192] });
139193
=== added file 'lib/lp/registry/javascript/sharing/sharingdetailsview.js'
--- lib/lp/registry/javascript/sharing/sharingdetailsview.js 1970-01-01 00:00:00 +0000
+++ lib/lp/registry/javascript/sharing/sharingdetailsview.js 2012-04-04 05:02:23 +0000
@@ -0,0 +1,202 @@
1/* Copyright 2012 Canonical Ltd. This software is licensed under the
2 * GNU Affero General Public License version 3 (see the file LICENSE).
3 *
4 * Disclosure infrastructure.
5 *
6 * @module lp.registry.sharing
7 */
8
9YUI.add('lp.registry.sharing.sharingdetailsview', function(Y) {
10
11var namespace = Y.namespace('lp.registry.sharing.sharingdetailsview');
12
13function SharingDetailsView(config) {
14 SharingDetailsView.superclass.constructor.apply(this, arguments);
15}
16
17SharingDetailsView.ATTRS = {
18 lp_client: {
19 value: new Y.lp.client.Launchpad()
20 },
21
22 write_enabled: {
23 value: false
24 },
25
26 sharing_details_table: {
27 value: null
28 }
29};
30
31Y.extend(SharingDetailsView, Y.Widget, {
32
33 initializer: function(config) {
34 if (LP.cache.sharing_write_enabled !== true) {
35 return;
36 }
37 this.set('write_enabled', true);
38 },
39
40 renderUI: function() {
41 var ns = Y.lp.registry.sharing.sharingdetails;
42 var details_table = new ns.SharingDetailsTable({
43 bugs: LP.cache.bugs,
44 branches: LP.cache.branches,
45 person_name: LP.cache.sharee.displayname,
46 write_enabled: this.get('write_enabled')
47 });
48 this.set('sharing_details_table', details_table);
49 details_table.render();
50 },
51
52 bindUI: function() {
53 if (!this.get('write_enabled')) {
54 return;
55 }
56 var self = this;
57 var sharing_details_table = this.get('sharing_details_table');
58 var ns = Y.lp.registry.sharing.sharingdetails;
59 sharing_details_table.subscribe(
60 ns.SharingDetailsTable.REMOVE_GRANT, function(e) {
61 self.confirm_grant_removal(
62 e.details[0], e.details[1], e.details[2], e.details[3]);
63 });
64 },
65
66 syncUI: function() {
67 var sharing_details_table = this.get('sharing_details_table');
68 sharing_details_table.syncUI();
69 },
70
71 /**
72 * Show a spinner next to the delete icon.
73 *
74 * @method _show_delete_spinner
75 */
76 _show_delete_spinner: function(delete_link) {
77 var spinner_node = Y.Node.create(
78 '<img class="spinner" src="/@@/spinner" alt="Removing..." />');
79 delete_link.insertBefore(spinner_node, delete_link);
80 delete_link.addClass('unseen');
81 },
82
83 /**
84 * Hide the delete spinner.
85 *
86 * @method _hide_delete_spinner
87 */
88 _hide_delete_spinner: function(delete_link) {
89 delete_link.removeClass('unseen');
90 var spinner = delete_link.get('parentNode').one('.spinner');
91 if (Y.Lang.isValue(spinner)) {
92 spinner.remove();
93 }
94 },
95
96 /**
97 * Prompt the user to confirm the removal of access to the selected
98 * artifact.
99 *
100 * @method confirm_grant_removal
101 * @param delete_link
102 * @param artifact_uri
103 * @param artifact_name
104 * @param artifact_type
105 */
106 confirm_grant_removal: function(delete_link, artifact_uri,
107 artifact_name, artifact_type) {
108 var confirm_text_template = [
109 '<p class="large-warning" style="padding:2px 2px 15px 36px;">',
110 ' Do you really want to stop sharing',
111 ' "{artifact}" with {person_name}?',
112 '</p>'
113 ].join('');
114 var person_name = LP.cache.sharee.displayname;
115 var confirm_text = Y.Lang.sub(confirm_text_template,
116 {artifact: artifact_name,
117 person_name: person_name});
118 var self = this;
119 var co = new Y.lp.app.confirmationoverlay.ConfirmationOverlay({
120 submit_fn: function() {
121 self.perform_remove_grant(
122 delete_link, artifact_uri, artifact_type);
123 },
124 form_content: confirm_text,
125 headerContent: '<h2>Stop sharing</h2>'
126 });
127 co.show();
128 },
129
130 /**
131 * The server call to remove the specified sharee has succeeded.
132 * Update the model and view.
133 * @method remove_grant_success
134 * @param artifact_uri
135 */
136 remove_grant_success: function(artifact_uri) {
137 var bugs_data = LP.cache.bugs;
138 var self = this;
139 Y.Array.some(bugs_data, function(bug, index) {
140 if (bug.self_link === artifact_uri) {
141 bugs_data.splice(index, 1);
142 self.syncUI();
143 return true;
144 }
145 });
146 var branch_data = LP.cache.branches;
147 Y.Array.some(branch_data, function(branch, index) {
148 if (branch.self_link === artifact_uri) {
149 branch_data.splice(index, 1);
150 self.syncUI();
151 return true;
152 }
153 });
154 },
155
156 /**
157 * Make a server call to remove access to the specified artifact.
158 * @method perform_remove_sharee
159 * @param delete_link
160 * @param artifact_uri
161 * @param artifact_type
162 */
163 perform_remove_grant: function(delete_link, artifact_uri, artifact_type) {
164 var error_handler = new Y.lp.client.ErrorHandler();
165 var bugs = [];
166 var branches = [];
167 if (artifact_type === 'bug') {
168 bugs = [artifact_uri];
169 } else {
170 branches = [artifact_uri];
171 }
172 var self = this;
173 var y_config = {
174 on: {
175 start: Y.bind(
176 self._show_delete_spinner, namespace, delete_link),
177 end: Y.bind(self._hide_delete_spinner, namespace, delete_link),
178 success: function() {
179 self.remove_grant_success(artifact_uri);
180 },
181 failure: error_handler.getFailureHandler()
182 },
183 parameters: {
184 pillar: LP.cache.pillar.self_link,
185 sharee: LP.cache.sharee.self_link,
186 bugs: bugs,
187 branches: branches
188 }
189 };
190 this.get('lp_client').named_post(
191 '/+services/sharing', 'revokeAccessGrants', y_config);
192 }
193});
194
195SharingDetailsView.NAME = 'sharingDetailsView';
196namespace.SharingDetailsView = SharingDetailsView;
197
198}, "0.1", { "requires": [
199 'node', 'selector-css3', 'lp.client', 'lp.mustache',
200 'lp.registry.sharing.sharingdetails', 'lp.app.confirmationoverlay'
201 ]});
202
0203
=== modified file 'lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js'
--- lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js 2012-03-31 11:32:15 +0000
+++ lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js 2012-04-04 05:02:23 +0000
@@ -60,7 +60,7 @@
6060
61 test_library_exists: function () {61 test_library_exists: function () {
62 Y.Assert.isObject(Y.lp.registry.sharing.pillarsharingview,62 Y.Assert.isObject(Y.lp.registry.sharing.pillarsharingview,
63 "We should be able to locate the " +63 "Could not locate the " +
64 "lp.registry.sharing.pillarsharingview module");64 "lp.registry.sharing.pillarsharingview module");
65 },65 },
6666
6767
=== modified file 'lib/lp/registry/javascript/sharing/tests/test_shareelisting_navigator.js'
--- lib/lp/registry/javascript/sharing/tests/test_shareelisting_navigator.js 2012-03-20 06:11:07 +0000
+++ lib/lp/registry/javascript/sharing/tests/test_shareelisting_navigator.js 2012-04-04 05:02:23 +0000
@@ -36,7 +36,7 @@
3636
37 test_library_exists: function () {37 test_library_exists: function () {
38 Y.Assert.isObject(Y.lp.registry.sharing.shareelisting_navigator,38 Y.Assert.isObject(Y.lp.registry.sharing.shareelisting_navigator,
39 "We should be able to locate the " +39 "Could not locate the " +
40 "lp.registry.sharing.shareelisting_navigator module");40 "lp.registry.sharing.shareelisting_navigator module");
41 },41 },
4242
4343
=== modified file 'lib/lp/registry/javascript/sharing/tests/test_shareepicker.js'
--- lib/lp/registry/javascript/sharing/tests/test_shareepicker.js 2012-03-27 02:27:21 +0000
+++ lib/lp/registry/javascript/sharing/tests/test_shareepicker.js 2012-04-04 05:02:23 +0000
@@ -76,7 +76,7 @@
7676
77 test_library_exists: function () {77 test_library_exists: function () {
78 Y.Assert.isObject(Y.lp.registry.sharing.shareepicker,78 Y.Assert.isObject(Y.lp.registry.sharing.shareepicker,
79 "We should be able to locate the " +79 "Could not locate the " +
80 "lp.registry.sharing module");80 "lp.registry.sharing module");
81 },81 },
8282
8383
=== modified file 'lib/lp/registry/javascript/sharing/tests/test_shareetable.js'
--- lib/lp/registry/javascript/sharing/tests/test_shareetable.js 2012-04-02 23:55:58 +0000
+++ lib/lp/registry/javascript/sharing/tests/test_shareetable.js 2012-04-04 05:02:23 +0000
@@ -69,7 +69,7 @@
6969
70 test_library_exists: function () {70 test_library_exists: function () {
71 Y.Assert.isObject(Y.lp.registry.sharing.shareetable,71 Y.Assert.isObject(Y.lp.registry.sharing.shareetable,
72 "We should be able to locate the " +72 "Could not locate the " +
73 "lp.registry.sharing.shareetable module");73 "lp.registry.sharing.shareetable module");
74 },74 },
7575
7676
=== renamed file 'lib/lp/registry/javascript/sharing/tests/test_sharing_details.html' => 'lib/lp/registry/javascript/sharing/tests/test_sharingdetails.html'
--- lib/lp/registry/javascript/sharing/tests/test_sharing_details.html 2012-03-27 15:10:21 +0000
+++ lib/lp/registry/javascript/sharing/tests/test_sharingdetails.html 2012-04-04 05:02:23 +0000
@@ -34,18 +34,20 @@
34 <script type="text/javascript" src="../sharingdetails.js"></script>34 <script type="text/javascript" src="../sharingdetails.js"></script>
3535
36 <!-- The test suite. -->36 <!-- The test suite. -->
37 <script type="text/javascript" src="test_sharing_details.js"></script>37 <script type="text/javascript" src="test_sharingdetails.js"></script>
3838
39 </head>39 </head>
40 <body class="yui3-skin-sam">40 <body class="yui3-skin-sam">
41 <!-- The example markup required by the script to run -->41 <!-- The example markup required by the script to run -->
42 <ul id="suites">42 <ul id="suites">
43 <li>lp.registry.sharing.details.test</li>43 <li>lp.registry.sharing.sharingdetails.test</li>
44 </ul>44 </ul>
45 <table>45 <div id="fixture"></div>
46 <tbody id="sharing-table-body">46 <script type="text/x-template" id="sharing-table-template">
47 </tbody>47 <table>
48 </table>48 <tbody id="sharing-table-body">
4949 </tbody>
50 </table>
51 </script>
50 </body>52 </body>
51</html>53</html>
5254
=== renamed file 'lib/lp/registry/javascript/sharing/tests/test_sharing_details.js' => 'lib/lp/registry/javascript/sharing/tests/test_sharingdetails.js'
--- lib/lp/registry/javascript/sharing/tests/test_sharing_details.js 2012-03-27 20:45:36 +0000
+++ lib/lp/registry/javascript/sharing/tests/test_sharingdetails.js 2012-04-04 05:02:23 +0000
@@ -1,70 +1,173 @@
1/* Copyright (c) 2012, Canonical Ltd. All rights reserved. */1/* Copyright (c) 2012, Canonical Ltd. All rights reserved. */
2YUI.add('lp.registry.sharing.details.test', function(Y) {2YUI.add('lp.registry.sharing.sharingdetails.test', function(Y) {
33
4// Local aliases4// Local aliases
5 var Assert = Y.Assert,5 var Assert = Y.Assert;
6 ArrayAssert = Y.ArrayAssert;6 var sharing_details = Y.lp.registry.sharing.sharingdetails;
7 var sharing_details = Y.lp.registry.sharing.details;
87
9 var tests = Y.namespace('lp.registry.sharing.details.test');8 var tests = Y.namespace('lp.registry.sharing.sharingdetails.test');
10 tests.suite = new Y.Test.Suite(9 tests.suite = new Y.Test.Suite(
11 "lp.registry.sharing.details Tests");10 "lp.registry.sharing.sharingdetails Tests");
1211
13 tests.suite.add(new Y.Test.Case({12 tests.suite.add(new Y.Test.Case({
14 name: 'Sharing Details',13 name: 'Sharing Details',
1514
16 setUp: function() {15 setUp: function () {
17 window.LP = {16 window.LP = {
18 links: {},17 links: {},
19 cache: {}18 cache: {
19 bugs: [
20 {
21 self_link: 'api/devel/bugs/2',
22 web_link:'/bugs/2',
23 bug_id: '2',
24 bug_importance: 'critical',
25 bug_summary:'Everything is broken.'
26 }
27 ],
28 branches: [
29 {
30 self_link: 'api/devel/~someone/+junk/somebranch',
31 web_link:'/~someone/+junk/somebranch',
32 branch_id: '2',
33 branch_name:'lp:~someone/+junk/somebranch'
34 }
35 ]
36 }
20 };37 };
21 },38 this.fixture = Y.one('#fixture');
2239 var sharing_table = Y.Node.create(
23 tearDown: function() {40 Y.one('#sharing-table-template').getContent());
24 },41 this.fixture.appendChild(sharing_table);
2542
43 },
44
45 tearDown: function () {
46 if (this.fixture !== null) {
47 this.fixture.empty(true);
48 }
49 delete this.fixture;
50 delete window.LP;
51 },
52
53 _create_Widget: function(overrides) {
54 if (!Y.Lang.isValue(overrides)) {
55 overrides = {};
56 }
57 var config = Y.merge({
58 person_name: 'Fred',
59 bugs: window.LP.cache.bugs,
60 branches: window.LP.cache.branches,
61 write_enabled: true
62 }, overrides);
63 window.LP.cache.sharee_data = config.sharees;
64 return new sharing_details.SharingDetailsTable(config);
65 },
66
67 test_library_exists: function () {
68 Y.Assert.isObject(Y.lp.registry.sharing.sharingdetails,
69 "Could not locate the " +
70 "lp.registry.sharing.sharingdetails module");
71 },
72
73 test_widget_can_be_instantiated: function() {
74 this.details_widget = this._create_Widget();
75 Y.Assert.isInstanceOf(
76 Y.lp.registry.sharing.sharingdetails.SharingDetailsTable,
77 this.details_widget,
78 "Sharing details table failed to be instantiated");
79 },
80
81 // Read only mode disables the correct things.
82 test_readonly: function() {
83 this.details_widget = this._create_Widget({
84 write_enabled: false
85 });
86 this.details_widget.render();
87 Y.all('#sharing-table-body .sprite.remove a')
88 .each(function(link) {
89 Y.Assert.isTrue(link.hasClass('unseen'));
90 });
91 },
92
93 // Test that branches are correctly rendered.
26 test_render_branches: function () {94 test_render_branches: function () {
27 var config = {95 this.details_widget = this._create_Widget();
28 branches: [96 this.details_widget.render();
29 {
30 branch_link:'/~someone/+junk/somebranch',
31 branch_id: '2',
32 branch_name:'lp:~someone/+junk/somebranch'
33 }
34 ]
35 };
36 details_module = Y.lp.registry.sharing.details;
37 table_constructor = details_module.SharingDetailsTable;
38 var details_widget = new table_constructor(config);
39 details_widget.render();
40 var expected = "lp:~someone/+junk/somebranch";97 var expected = "lp:~someone/+junk/somebranch";
41 var branch_link = Y.one('#sharing-table-body').one('a');98 var web_link = Y.one(
42 var actual_text = branch_link.get('text').replace(/\s+/g, '');99 '#sharing-table-body tr#shared-branch-2').one('a');
100 var actual_text = web_link.get('text').replace(/\s+/g, '');
43 Assert.areEqual(expected, actual_text);101 Assert.areEqual(expected, actual_text);
44 },102 },
45103
104 // Test that bugs are correctly rendered.
46 test_render_bugs: function () {105 test_render_bugs: function () {
47 var config = {106 this.details_widget = this._create_Widget();
48 bugs: [107 this.details_widget.render();
49 {
50 bug_link:'/bugs/2',
51 bug_id: '2',
52 bug_importance: 'critical',
53 bug_summary:'Everything is broken.'
54 }
55 ]
56 };
57 details_module = Y.lp.registry.sharing.details;
58 table_constructor = details_module.SharingDetailsTable;
59 var details_widget = new table_constructor(config);
60 details_widget.render();
61 var expected = "Everythingisbroken.";108 var expected = "Everythingisbroken.";
62 var bug_link = Y.one('#sharing-table-body').one('a');109 var web_link = Y.one(
63 var actual_text = bug_link.get('text').replace(/\s+/g, '');110 '#sharing-table-body tr#shared-bug-2').one('a');
111 var actual_text = web_link.get('text').replace(/\s+/g, '');
64 Assert.areEqual(expected, actual_text);112 Assert.areEqual(expected, actual_text);
113 },
114
115 // When the bug revoke link is clicked, the correct event is published.
116 test_bug_revoke_click: function() {
117 this.details_widget = this._create_Widget();
118 this.details_widget.render();
119 var event_fired = false;
120 this.details_widget.subscribe(
121 sharing_details.SharingDetailsTable.REMOVE_GRANT,
122 function(e) {
123 var delete_link = e.details[0];
124 var artifact_uri = e.details[1];
125 var artifact_name = e.details[2];
126 var artifact_type = e.details[3];
127 Y.Assert.areEqual('api/devel/bugs/2', artifact_uri);
128 Y.Assert.areEqual('Bug 2', artifact_name);
129 Y.Assert.areEqual('bug', artifact_type);
130 Y.Assert.areEqual(delete_link_to_click, delete_link);
131 event_fired = true;
132 }
133 );
134 var delete_link_to_click =
135 Y.one('#sharing-table-body span[id=remove-bug-2] a');
136 delete_link_to_click.simulate('click');
137 Y.Assert.isTrue(event_fired);
138 },
139
140 // When the branch revoke link is clicked, the correct event is
141 // published.
142 test_branch_revoke_click: function() {
143 this.details_widget = this._create_Widget();
144 this.details_widget.render();
145 var event_fired = false;
146 this.details_widget.subscribe(
147 sharing_details.SharingDetailsTable.REMOVE_GRANT,
148 function(e) {
149 var delete_link = e.details[0];
150 var artifact_uri = e.details[1];
151 var artifact_name = e.details[2];
152 var artifact_type = e.details[3];
153 Y.Assert.areEqual(
154 'api/devel/~someone/+junk/somebranch',
155 artifact_uri);
156 Y.Assert.areEqual(
157 'lp:~someone/+junk/somebranch', artifact_name);
158 Y.Assert.areEqual('branch', artifact_type);
159 Y.Assert.areEqual(delete_link_to_click, delete_link);
160 event_fired = true;
161 }
162 );
163 var delete_link_to_click =
164 Y.one('#sharing-table-body span[id=remove-branch-2] a');
165 delete_link_to_click.simulate('click');
166 Y.Assert.isTrue(event_fired);
65 }167 }
66 }));168 }));
67169
68170
69}, '0.1', { 'requires': [ 'test', 'console', 'event',171}, '0.1', { 'requires':
70 'lp.registry.sharing.details']});172 [ 'test', 'console', 'event', 'node-event-simulate',
173 'lp.registry.sharing.sharingdetails']});
71174
=== added file 'lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.html'
--- lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.html 1970-01-01 00:00:00 +0000
+++ lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.html 2012-04-04 05:02:23 +0000
@@ -0,0 +1,66 @@
1<!DOCTYPE html>
2<!--
3Copyright 2012 Canonical Ltd. This software is licensed under the
4GNU Affero General Public License version 3 (see the file LICENSE).
5-->
6
7<html>
8 <head>
9 <title>Sharing Details View Tests</title>
10
11 <!-- YUI and test setup -->
12 <script type="text/javascript"
13 src="../../../../../../build/js/yui/yui/yui.js">
14 </script>
15 <link rel="stylesheet"
16 href="../../../../../../build/js/yui/console/assets/console-core.css" />
17 <link rel="stylesheet"
18 href="../../../../../../build/js/yui/console/assets/skins/sam/console.css" />
19 <link rel="stylesheet"
20 href="../../../../../../build/js/yui/test/assets/skins/sam/test.css" />
21
22 <script type="text/javascript"
23 src="../../../../../../build/js/lp/app/testing/testrunner.js"></script>
24
25 <link rel="stylesheet" href="../../../../app/javascript/testing/test.css" />
26
27 <!-- Dependencies -->
28 <script type="text/javascript"
29 src="../../../../../../build/js/lp/app/testing/mockio.js"></script>
30 <script type="text/javascript"
31 src="../../../../../../build/js/lp/app/client.js"></script>
32 <script type="text/javascript"
33 src="../../../../../../build/js/lp/app/confirmationoverlay/confirmationoverlay.js"></script>
34 <script type="text/javascript"
35 src="../../../../../../build/js/lp/app/mustache.js"></script>
36 <script type="text/javascript"
37 src="../../../../../../build/js/lp/app/formoverlay/formoverlay.js"></script>
38 <script type="text/javascript"
39 src="../../../../../../build/js/lp/app/overlay/overlay.js"></script>
40 <script type="text/javascript"
41 src="../../../../../../build/js/lp/registry/sharing/sharingdetails.js"></script>
42
43 <!-- The module under test. -->
44 <script type="text/javascript" src="../sharingdetailsview.js"></script>
45
46 <!-- The test suite -->
47 <script type="text/javascript" src="test_sharingdetailsview.js"></script>
48
49 <script id="test-fixture" type="text/x-template">
50 <table id='sharing-details-table'></table>
51 </script>
52 </head>
53 <body class="yui3-skin-sam">
54 <ul id="suites">
55 <li>lp.registry.sharing.sharingdetailsview.test</li>
56 </ul>
57 <div id='fixture'>
58 </div>
59 <script type="text/x-template" id="sharing-table-template">
60 <table>
61 <tbody id="sharing-table-body">
62 </tbody>
63 </table>
64 </script>
65 </body>
66</html>
067
=== added file 'lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js'
--- lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js 1970-01-01 00:00:00 +0000
+++ lib/lp/registry/javascript/sharing/tests/test_sharingdetailsview.js 2012-04-04 05:02:23 +0000
@@ -0,0 +1,305 @@
1/* Copyright (c) 2012, Canonical Ltd. All rights reserved. */
2
3YUI.add('lp.registry.sharing.sharingdetailsview.test', function (Y) {
4
5 var tests = Y.namespace('lp.registry.sharing.sharingdetailsview.test');
6 tests.suite = new Y.Test.Suite(
7 'lp.registry.sharing.sharingdetailsview Tests');
8
9 tests.suite.add(new Y.Test.Case({
10 name: 'lp.registry.sharing.sharingdetailsview_tests',
11
12 setUp: function () {
13 window.LP = {
14 links: {},
15 cache: {
16 bugs: [
17 {
18 self_link: 'api/devel/bugs/2',
19 web_link:'/bugs/2',
20 bug_id: '2',
21 bug_importance: 'critical',
22 bug_summary:'Everything is broken.'
23 }
24 ],
25 branches: [
26 {
27 self_link: 'api/devel/~someone/+junk/somebranch',
28 web_link:'/~someone/+junk/somebranch',
29 branch_id: '2',
30 branch_name:'lp:~someone/+junk/somebranch'
31 }
32 ],
33 sharee: {
34 displayname: 'Fred Bloggs',
35 self_link: '~fred'
36 },
37 pillar: {
38 self_link: '/pillar'
39 },
40 sharing_write_enabled: true
41 }
42 };
43 this.fixture = Y.one('#fixture');
44 var sharee_table = Y.Node.create(
45 Y.one('#sharing-table-template').getContent());
46 this.fixture.appendChild(sharee_table);
47 },
48
49 tearDown: function () {
50 Y.one('#fixture').empty(true);
51 delete window.LP;
52 },
53
54 _create_Widget: function(cfg) {
55 var ns = Y.lp.registry.sharing.sharingdetailsview;
56 return new ns.SharingDetailsView(cfg);
57 },
58
59 test_library_exists: function () {
60 Y.Assert.isObject(Y.lp.registry.sharing.sharingdetailsview,
61 "Could not locate the " +
62 "lp.registry.sharing.sharingdetailsview module");
63 },
64
65 test_widget_can_be_instantiated: function() {
66 this.view = this._create_Widget();
67 Y.Assert.isInstanceOf(
68 Y.lp.registry.sharing.sharingdetailsview.SharingDetailsView,
69 this.view,
70 "Sharing details view failed to be instantiated");
71 },
72
73 // The view is correctly rendered.
74 test_render: function() {
75 this.view = this._create_Widget();
76 this.view.render();
77 // The sharing details table - we'll just check one row
78 Y.Assert.isNotNull(
79 Y.one('#sharing-table-body tr[id=shared-bug-2]'));
80 },
81
82 // Read only mode disables the correct things.
83 test_readonly: function() {
84 window.LP.cache.sharing_write_enabled = false;
85 this.view = this._create_Widget();
86 this.view.render();
87 Y.Assert.isFalse(
88 this.view.get('sharing_details_table')
89 .get('write_enabled'));
90 },
91
92 // Clicking a bug remove link calls the confirm_grant_removal
93 // method with the correct parameters.
94 test_remove_bug_grant_click: function() {
95 this.view = this._create_Widget();
96 this.view.render();
97 var confirmRemove_called = false;
98 this.view.confirm_grant_removal = function(
99 delete_link, artifact_uri, artifact_name, artifact_type) {
100 Y.Assert.areEqual('api/devel/bugs/2', artifact_uri);
101 Y.Assert.areEqual('Bug 2', artifact_name);
102 Y.Assert.areEqual('bug', artifact_type);
103 Y.Assert.areEqual(delete_link_to_click, delete_link);
104 confirmRemove_called = true;
105
106 };
107 var delete_link_to_click =
108 Y.one('#sharing-table-body span[id=remove-bug-2] a');
109 delete_link_to_click.simulate('click');
110 Y.Assert.isTrue(confirmRemove_called);
111 },
112
113 // Clicking a bug remove link calls the confirm_grant_removal
114 // method with the correct parameters.
115 test_remove_branch_grant_click: function() {
116 this.view = this._create_Widget();
117 this.view.render();
118 var confirmRemove_called = false;
119 this.view.confirm_grant_removal = function(
120 delete_link, artifact_uri, artifact_name, artifact_type) {
121 Y.Assert.areEqual(
122 'api/devel/~someone/+junk/somebranch', artifact_uri);
123 Y.Assert.areEqual(
124 'lp:~someone/+junk/somebranch', artifact_name);
125 Y.Assert.areEqual('branch', artifact_type);
126 Y.Assert.areEqual(delete_link_to_click, delete_link);
127 confirmRemove_called = true;
128
129 };
130 var delete_link_to_click =
131 Y.one('#sharing-table-body span[id=remove-branch-2] a');
132 delete_link_to_click.simulate('click');
133 Y.Assert.isTrue(confirmRemove_called);
134 },
135
136 //Test the behaviour of the removal confirmation dialog.
137 _test_confirm_grant_removal: function(click_ok) {
138 this.view = this._create_Widget();
139 this.view.render();
140 var performRemove_called = false;
141 this.view.perform_remove_grant = function(
142 delete_link, artifact_uri, artifact_type) {
143 Y.Assert.areEqual('api/devel/bugs/2', artifact_uri);
144 Y.Assert.areEqual('bug', artifact_type);
145 Y.Assert.areEqual(artifact_delete_link, delete_link);
146 performRemove_called = true;
147
148 };
149 var artifact_delete_link =
150 Y.one('#sharing-table-body td[id=remove-bug-2] a');
151 this.view.confirm_grant_removal(
152 artifact_delete_link, 'api/devel/bugs/2', 'Bug 2', 'bug');
153 var co = Y.one('.yui3-overlay.yui3-lp-app-confirmationoverlay');
154 var actions = co.one('.yui3-lazr-formoverlay-actions');
155 var btn_style;
156 if (click_ok) {
157 btn_style = '.ok-btn';
158 } else {
159 btn_style = '.cancel-btn';
160 }
161 var button = actions.one(btn_style);
162 button.simulate('click');
163 Y.Assert.areEqual(click_ok, performRemove_called);
164 Y.Assert.isTrue(
165 co.hasClass('yui3-lp-app-confirmationoverlay-hidden'));
166 },
167
168 //Test the remove confirmation dialog when the user clicks Ok.
169 test_confirm_sharee_removal_ok: function() {
170 this._test_confirm_grant_removal(true);
171 },
172
173 //Test the remove confirmation dialog when the user clicks Cancel.
174 test_confirm_sharee_removal_cancel: function() {
175 this._test_confirm_grant_removal(false);
176 },
177
178 // The perform_remove_grant method makes the expected XHR calls when a
179 // bug grant remove link is clicked.
180 test_perform_remove_bug_grant: function() {
181 var mockio = new Y.lp.testing.mockio.MockIo();
182 var lp_client = new Y.lp.client.Launchpad({
183 io_provider: mockio
184 });
185 this.view = this._create_Widget({
186 lp_client: lp_client
187 });
188 this.view.render();
189 var remove_grant_success_called = false;
190 var self = this;
191 this.view.remove_grant_success = function(artifact_uri) {
192 Y.Assert.areEqual('api/devel/bugs/2', artifact_uri);
193 remove_grant_success_called = true;
194 };
195 var delete_link =
196 Y.one('#sharing-table-body span[id=remove-bug-2] a');
197 this.view.perform_remove_grant(
198 delete_link, 'api/devel/bugs/2', 'bug');
199 Y.Assert.areEqual(
200 '/api/devel/+services/sharing',
201 mockio.last_request.url);
202 var expected_qs = '';
203 expected_qs = Y.lp.client.append_qs(
204 expected_qs, 'ws.op', 'revokeAccessGrants');
205 expected_qs = Y.lp.client.append_qs(
206 expected_qs, 'pillar', '/pillar');
207 expected_qs = Y.lp.client.append_qs(
208 expected_qs, 'sharee', '~fred');
209 expected_qs = Y.lp.client.append_qs(
210 expected_qs, 'bugs', 'api/devel/bugs/2');
211 Y.Assert.areEqual(expected_qs, mockio.last_request.config.data);
212 mockio.last_request.successJSON({});
213 Y.Assert.isTrue(remove_grant_success_called);
214 },
215
216 // The perform_remove_grant method makes the expected XHR calls when a
217 // branch grant remove link is clicked.
218 test_perform_remove_branch_grant: function() {
219 var mockio = new Y.lp.testing.mockio.MockIo();
220 var lp_client = new Y.lp.client.Launchpad({
221 io_provider: mockio
222 });
223 this.view = this._create_Widget({
224 lp_client: lp_client
225 });
226 this.view.render();
227 var remove_grant_success_called = false;
228 var self = this;
229 this.view.remove_grant_success = function(artifact_uri) {
230 Y.Assert.areEqual(
231 'api/devel/~someone/+junk/somebranch', artifact_uri);
232 remove_grant_success_called = true;
233 };
234 var delete_link =
235 Y.one('#sharing-table-body span[id=remove-branch-2] a');
236 this.view.perform_remove_grant(
237 delete_link, 'api/devel/~someone/+junk/somebranch', 'branch');
238 Y.Assert.areEqual(
239 '/api/devel/+services/sharing',
240 mockio.last_request.url);
241 var expected_qs = '';
242 expected_qs = Y.lp.client.append_qs(
243 expected_qs, 'ws.op', 'revokeAccessGrants');
244 expected_qs = Y.lp.client.append_qs(
245 expected_qs, 'pillar', '/pillar');
246 expected_qs = Y.lp.client.append_qs(
247 expected_qs, 'sharee', '~fred');
248 expected_qs = Y.lp.client.append_qs(
249 expected_qs, 'branches', 'api/devel/~someone/+junk/somebranch');
250 Y.Assert.areEqual(expected_qs, mockio.last_request.config.data);
251 mockio.last_request.successJSON({});
252 Y.Assert.isTrue(remove_grant_success_called);
253 },
254
255 // The remove bug grant callback updates the model and syncs the UI.
256 test_remove_bug_grant_success: function() {
257 this.view = this._create_Widget({anim_duration: 0});
258 this.view.render();
259 var syncUI_called = false;
260 this.view.syncUI = function() {
261 syncUI_called = true;
262 };
263 this.view.remove_grant_success('api/devel/bugs/2');
264 Y.Assert.isTrue(syncUI_called);
265 Y.Array.each(window.LP.cache.bugs,
266 function(bug) {
267 Y.Assert.areNotEqual(2, bug.bug_id);
268 });
269 },
270
271 // The remove branch grant callback updates the model and syncs the UI.
272 test_remove_branch_grant_success: function() {
273 this.view = this._create_Widget({anim_duration: 0});
274 this.view.render();
275 var syncUI_called = false;
276 this.view.syncUI = function() {
277 syncUI_called = true;
278 };
279 this.view.remove_grant_success(
280 'api/devel/~someone/+junk/somebranch');
281 Y.Assert.isTrue(syncUI_called);
282 Y.Array.each(window.LP.cache.branches,
283 function(branch) {
284 Y.Assert.areNotEqual(2, branch.branch_id);
285 });
286 },
287
288 // Test that syncUI works as expected.
289 test_syncUI: function() {
290 this.view = this._create_Widget();
291 this.view.render();
292 var sharee_table = this.view.get('sharing_details_table');
293 var table_syncUI_called = false;
294 sharee_table.syncUI = function() {
295 table_syncUI_called = true;
296 };
297 this.view.syncUI();
298 Y.Assert.isTrue(table_syncUI_called);
299 }
300 }));
301
302}, '0.1', {'requires': ['test', 'console', 'event', 'node-event-simulate',
303 'lp.testing.mockio',
304 'lp.registry.sharing.sharingdetails',
305 'lp.registry.sharing.sharingdetailsview']});
0306
=== modified file 'lib/lp/registry/javascript/tests/test_team.js'
--- lib/lp/registry/javascript/tests/test_team.js 2012-03-02 20:19:50 +0000
+++ lib/lp/registry/javascript/tests/test_team.js 2012-04-04 05:02:23 +0000
@@ -22,7 +22,7 @@
2222
23 test_library_exists: function() {23 test_library_exists: function() {
24 Y.Assert.isObject(Y.lp.registry.team,24 Y.Assert.isObject(Y.lp.registry.team,
25 "We should be able to locate the lp.registry.team module");25 "Could not locate the lp.registry.team module");
26 },26 },
2727
28 // The initialise_team_edit() method invokes the visibility_changed()28 // The initialise_team_edit() method invokes the visibility_changed()
2929
=== modified file 'lib/lp/registry/templates/pillar-sharing-details.pt'
--- lib/lp/registry/templates/pillar-sharing-details.pt 2012-03-27 21:12:27 +0000
+++ lib/lp/registry/templates/pillar-sharing-details.pt 2012-04-04 05:02:23 +0000
@@ -10,17 +10,12 @@
10<head>10<head>
11 <metal:block fill-slot="head_epilogue">11 <metal:block fill-slot="head_epilogue">
12 <script>12 <script>
13 LPJS.use('base', 'node', 'event', 'lp.registry.sharing.details',13 LPJS.use('base', 'node', 'event', 'lp.registry.sharing.sharingdetailsview',
14 function(Y) {14 function(Y) {
15 Y.on('domready', function() {15 Y.on('domready', function() {
16 var config = {16 var details_module = Y.lp.registry.sharing.sharingdetailsview;
17 branches: LP.cache.branches,17 var details_view = new details_module.SharingDetailsView();
18 bugs: LP.cache.bugs18 details_view.render();
19 };
20 var details_module = Y.lp.registry.sharing.details;
21 var details_widget = new details_module.SharingDetailsTable(
22 config);
23 details_widget.render();
24 });19 });
25 });20 });
26 </script>21 </script>
@@ -47,16 +42,12 @@
47 <col width="20px"/>42 <col width="20px"/>
48 <col width="auto"/>43 <col width="auto"/>
49 <col width="auto"/>44 <col width="auto"/>
50 <col width="30%"/>
51 <col width="auto"/>45 <col width="auto"/>
52 <thead>46 <thead>
53 <tr>47 <tr>
54 <th colspan="3" width="">48 <th colspan="4" width="">
55 <a href="#" class="sortheader">Bug Report or Branch</a>49 <a href="#" class="sortheader">Bug Report or Branch</a>
56 </th>50 </th>
57 <th colspan="2" width="">
58 <a href="#" class="sortheader">Via</a>
59 </th>
60 </tr>51 </tr>
61 </thead>52 </thead>
62 <tbody id="sharing-table-body"></tbody>53 <tbody id="sharing-table-body"></tbody>
6354
=== modified file 'standard_test_template.js'
--- standard_test_template.js 2012-02-03 17:15:44 +0000
+++ standard_test_template.js 2012-04-04 05:02:23 +0000
@@ -13,7 +13,7 @@
1313
14 test_library_exists: function () {14 test_library_exists: function () {
15 Y.Assert.isObject(Y.lp.${LIBRARY},15 Y.Assert.isObject(Y.lp.${LIBRARY},
16 "We should be able to locate the lp.${LIBRARY} module");16 "Could not locate the lp.${LIBRARY} module");
17 }17 }
1818
19 }));19 }));