Merge lp:~rharding/juju-gui/help-dropdown into lp:juju-gui/experimental

Proposed by Richard Harding
Status: Merged
Merged at revision: 1198
Proposed branch: lp:~rharding/juju-gui/help-dropdown
Merge into: lp:juju-gui/experimental
Diff against target: 1292 lines (+673/-259)
23 files modified
app/app.js (+22/-1)
app/assets/javascripts/view-dropdown-extension.js (+92/-0)
app/index.html (+4/-10)
app/modules-debug.js (+9/-0)
app/subapps/browser/browser.js (+13/-5)
app/templates/help-dropdown.handlebars (+29/-0)
app/templates/notifications.handlebars (+28/-24)
app/templates/onboarding.handlebars (+1/-1)
app/templates/overview.handlebars (+0/-4)
app/views/help-dropdown.js (+113/-0)
app/views/notifications.js (+15/-62)
app/views/onboarding.js (+13/-0)
bin/merge-files (+1/-0)
lib/views/browser/onboarding.less (+5/-0)
lib/views/dropdown.less (+110/-54)
lib/views/stylesheet.less (+6/-69)
test/index.html (+2/-0)
test/test_browser_app.js (+17/-0)
test/test_dropdown_extension.js (+80/-0)
test/test_help_dropdown.js (+97/-0)
test/test_notifications.js (+1/-28)
test/test_onboarding.js (+15/-0)
undocumented (+0/-1)
To merge this branch: bzr merge lp:~rharding/juju-gui/help-dropdown
Reviewer Review Type Date Requested Status
Juju GUI Hackers Pending
Review via email: mp+195116@code.launchpad.net

Description of the change

A dropdown view extension.

This is a refactoring of Huw's branch which created a dropdown widget
 and a "Help & Feedback" dropdown on the header bar.

 original: https://codereview.appspot.com/23410043/

 original original: https://codereview.appspot.com/25390043/

https://codereview.appspot.com/26200043/

To post a comment you must log in.
Revision history for this message
Richard Harding (rharding) wrote :

Reviewers: mp+195116_code.launchpad.net,

Message:
Please take a look.

Description:
A dropdown view extension.

This is a refactoring of Huw's branch which created a dropdown widget
  and a "Help & Feedback" dropdown on the header bar.

  original: https://codereview.appspot.com/23410043/

  original original: https://codereview.appspot.com/25390043/

https://code.launchpad.net/~rharding/juju-gui/help-dropdown/+merge/195116

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/26200043/

Affected files (+675, -259 lines):
   A [revision details]
   M app/app.js
   A app/assets/javascripts/view-dropdown-extension.js
   M app/index.html
   M app/modules-debug.js
   M app/subapps/browser/browser.js
   A app/templates/help-dropdown.handlebars
   M app/templates/notifications.handlebars
   M app/templates/onboarding.handlebars
   M app/templates/overview.handlebars
   A app/views/help-dropdown.js
   M app/views/notifications.js
   M app/views/onboarding.js
   M bin/merge-files
   M lib/views/browser/onboarding.less
   M lib/views/dropdown.less
   M lib/views/stylesheet.less
   M test/index.html
   M test/test_browser_app.js
   A test/test_dropdown_extension.js
   A test/test_help_dropdown.js
   M test/test_notifications.js
   M test/test_onboarding.js
   M undocumented

Revision history for this message
Richard Harding (rharding) wrote :
Revision history for this message
Richard Harding (rharding) wrote :

*** Submitted:

A dropdown view extension.

This is a refactoring of Huw's branch which created a dropdown widget
  and a "Help & Feedback" dropdown on the header bar.

  original: https://codereview.appspot.com/23410043/

  original original: https://codereview.appspot.com/25390043/

R=
CC=
https://codereview.appspot.com/26200043

https://codereview.appspot.com/26200043/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'app/app.js'
--- app/app.js 2013-11-07 21:10:06 +0000
+++ app/app.js 2013-11-13 18:41:54 +0000
@@ -126,7 +126,6 @@
126 type: 'juju.views.NotificationsView',126 type: 'juju.views.NotificationsView',
127 preserve: true127 preserve: true
128 }128 }
129
130 },129 },
131130
132 /*131 /*
@@ -534,6 +533,7 @@
534 } else {533 } else {
535 this.dispatch();534 this.dispatch();
536 }535 }
536 this._renderHelpDropdownView();
537 }, this);537 }, this);
538538
539 // Halt the default navigation on the juju logo to allow us to show539 // Halt the default navigation on the juju logo to allow us to show
@@ -613,6 +613,23 @@
613 },613 },
614614
615 /**615 /**
616 * Handles rendering the help dropdown view on application load.
617 *
618 * @method _renderHelpDropdownView
619 */
620 _renderHelpDropdownView: function() {
621 this.helpDropdown = new views.HelpDropdownView({
622 container: Y.one('#help-dropdown'),
623 env: this.db.environment
624 }).render();
625 // pass in onboarding when we no longer need to support
626 // fullscreen mode and interact with it directly
627 this.helpDropdown.on('navigate', function(e) {
628 this.navigate(e.url);
629 }, this);
630 },
631
632 /**
616 Calls the deployer import method with the bundle data633 Calls the deployer import method with the bundle data
617 to deploy the bundle to the environment.634 to deploy the bundle to the environment.
618635
@@ -674,6 +691,9 @@
674 @method destructor691 @method destructor
675 */692 */
676 destructor: function() {693 destructor: function() {
694 if (this.helpDropdown) {
695 this.helpDropdown.destroy();
696 }
677 if (this._keybindings) {697 if (this._keybindings) {
678 this._keybindings.detach();698 this._keybindings.detach();
679 }699 }
@@ -1344,6 +1364,7 @@
1344 'juju-ghost-inspector',1364 'juju-ghost-inspector',
1345 'juju-view-bundle',1365 'juju-view-bundle',
1346 'viewmode-controls',1366 'viewmode-controls',
1367 'help-dropdown',
1347 'bundle-import-extension'1368 'bundle-import-extension'
1348 ]1369 ]
1349});1370});
13501371
=== added file 'app/assets/javascripts/view-dropdown-extension.js'
--- app/assets/javascripts/view-dropdown-extension.js 1970-01-01 00:00:00 +0000
+++ app/assets/javascripts/view-dropdown-extension.js 2013-11-13 18:41:54 +0000
@@ -0,0 +1,92 @@
1/*
2This file is part of the Juju GUI, which lets users view and manage Juju
3environments within a graphical interface (https://launchpad.net/juju-gui).
4Copyright (C) 2012-2013 Canonical Ltd.
5
6This program is free software: you can redistribute it and/or modify it under
7the terms of the GNU Affero General Public License version 3, as published by
8the Free Software Foundation.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
12SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
13General Public License for more details.
14
15You should have received a copy of the GNU Affero General Public License along
16with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19'use strict';
20
21
22YUI.add('view-dropdown-extension', function(Y) {
23
24 /**
25 * Extension for a Y.View derrived class. Adds the dropdown
26 * functionality to the view. You need to call the _addDropdownFunc
27 * from the render method of the view to trigger because
28 * Y.View's do not offer any render event.
29 *
30 * @namespace juju
31 * @class Dropdown
32 */
33 function Dropdown() {}
34
35 Dropdown.prototype = {
36 /**
37 * Toggle the visibility of the dropdown panel.
38 *
39 * @method _toggleDropdown
40 * @param {Event} ev the click event from the control.
41 */
42 __toggleDropdown: function(ev) {
43 ev.halt();
44 this.get('container').toggleClass('open');
45 },
46
47 /**
48 * Hide the dropdown panel.
49 *
50 * @method close
51 */
52 __close: function() {
53 this.get('container').removeClass('open');
54 },
55
56 /**
57 * Sets up events and binds them to listeners.
58 *
59 * @method __bindUI
60 * @param {Y.Node} container The views container element.
61 */
62 __bindUI: function(container) {
63 this.addEvent(
64 container.one('.menu-link').on(
65 'click', this.__toggleDropdown, this));
66 this.addEvent(
67 container.on(
68 'clickoutside', this.__close, this));
69 },
70
71 /**
72 * Sets up the DOM nodes and renders them to the DOM.
73 *
74 * @method _addDropdownFunc
75 */
76 _addDropdownFunc: function() {
77 var container = this.get('container');
78 if (container) {
79 container.addClass('dropdown-menu');
80 this.__bindUI(container);
81 }
82 }
83 };
84
85 Y.namespace('juju').Dropdown = Dropdown;
86
87}, '0.1.0', {
88 requires: [
89 'event-tracker',
90 'view'
91 ]
92});
093
=== modified file 'app/index.html'
--- app/index.html 2013-11-07 16:50:47 +0000
+++ app/index.html 2013-11-13 18:41:54 +0000
@@ -147,19 +147,13 @@
147 </a>147 </a>
148 </li>148 </li>
149 <li class="notifications-nav">149 <li class="notifications-nav">
150 <div id="notifications"></div>150 <span id="notifications"></span>
151 <div class="notifier-box"></div>151 <span class="notifier-box"></span>
152 </li>152 </li>
153 </ul>153 </ul>
154 <ul class="right-nav">154 <ul class="right-nav">
155 <li class="help-dropdown">155 <li>
156 <a href="">156 <span id="help-dropdown"></span>
157 Help & Feedback
158 <span class="expand">
159 <i class="sprite chevron_down more"></i>
160 <i class="sprite chevron_up less hidden"></i>
161 </span>
162 </a>
163 </li>157 </li>
164 <li>158 <li>
165 <a href="" id="logout-trigger" class="button inverse">Logout</a>159 <a href="" id="logout-trigger" class="button inverse">Logout</a>
166160
=== modified file 'app/modules-debug.js'
--- app/modules-debug.js 2013-11-07 15:49:57 +0000
+++ app/modules-debug.js 2013-11-13 18:41:54 +0000
@@ -185,6 +185,10 @@
185 fullpath: '/juju-ui/assets/javascripts/bundle-import-extension.js'185 fullpath: '/juju-ui/assets/javascripts/bundle-import-extension.js'
186 },186 },
187187
188 'view-dropdown-extension': {
189 fullpath: '/juju-ui/assets/javascripts/view-dropdown-extension.js'
190 },
191
188 'sub-app': {192 'sub-app': {
189 fullpath: '/juju-ui/assets/javascripts/sub-app.js'193 fullpath: '/juju-ui/assets/javascripts/sub-app.js'
190 },194 },
@@ -233,6 +237,10 @@
233 fullpath: '/juju-ui/views/notifications.js'237 fullpath: '/juju-ui/views/notifications.js'
234 },238 },
235239
240 'juju-help-dropdown': {
241 fullpath: '/juju-ui/views/help-dropdown.js'
242 },
243
236 'juju-view-environment': {244 'juju-view-environment': {
237 fullpath: '/juju-ui/views/environment.js'245 fullpath: '/juju-ui/views/environment.js'
238 },246 },
@@ -267,6 +275,7 @@
267 'd3-components',275 'd3-components',
268 'juju-templates',276 'juju-templates',
269 'juju-notifications',277 'juju-notifications',
278 'juju-help-dropdown',
270 'juju-view-utils',279 'juju-view-utils',
271 'juju-topology',280 'juju-topology',
272 'juju-view-environment',281 'juju-view-environment',
273282
=== modified file 'app/subapps/browser/browser.js'
--- app/subapps/browser/browser.js 2013-11-05 18:10:05 +0000
+++ app/subapps/browser/browser.js 2013-11-13 18:41:54 +0000
@@ -626,13 +626,18 @@
626 * Create a 'welcome' message walkthrough for new users.626 * Create a 'welcome' message walkthrough for new users.
627 *627 *
628 * @method renderOnboarding628 * @method renderOnboarding
629 * @param {Boolean} force Whether it should force render the onboarding.
629 */630 */
630 renderOnboarding: function() {631 renderOnboarding: function(force) {
631 // Need to check onboarding exists due to the double dispatch bug.632 // Need to check onboarding exists due to the double dispatch bug.
632 this._onboarding = new Y.juju.views.OnboardingView({633 this._onboarding = new Y.juju.views.OnboardingView({
633 'container': '#onboarding'634 'container': '#onboarding'
634 });635 });
635636
637 if (force) {
638 this._onboarding.reset();
639 }
640
636 if (!this._onboarding.get('seen')) {641 if (!this._onboarding.get('seen')) {
637 this._onboarding.render();642 this._onboarding.render();
638 }643 }
@@ -861,10 +866,13 @@
861 // Only show the onboarding messaging if we're hitting the sidebar view866 // Only show the onboarding messaging if we're hitting the sidebar view
862 // without any extra url bits to the user. It's meant for a fresh user867 // without any extra url bits to the user. It's meant for a fresh user
863 // to see, not someone doing what they know they want to do.868 // to see, not someone doing what they know they want to do.
864 if (!this._onboarding) {869 var force = localStorage.getItem('force-onboarding');
865 if (!this._viewState.search &&870 // Reset force-onboarding so that the next request to /sidebar acts normal
866 !this._viewState.charmID) {871 localStorage.setItem('force-onboarding', '');
867 this.renderOnboarding();872
873 if (!this._onboarding || force) {
874 if (!this._viewState.search && !this._viewState.charmID) {
875 this.renderOnboarding(force);
868 }876 }
869 }877 }
870878
871879
=== added file 'app/templates/help-dropdown.handlebars'
--- app/templates/help-dropdown.handlebars 1970-01-01 00:00:00 +0000
+++ app/templates/help-dropdown.handlebars 2013-11-13 18:41:54 +0000
@@ -0,0 +1,29 @@
1<a href="" class="menu-link">
2 Help & feedback
3 <span class="expand">
4 <i class="sprite chevron_down more"></i>
5 <i class="sprite chevron_up less"></i>
6 </span>
7</a>
8<span class="dropdown right narrow">
9 <ul>
10 <li>
11 <a href="" class="start-onboarding">Tutorial</a>
12 </li>
13 <li>
14 <a href="http://juju.ubuntu.com/"
15 target="_blank">Visit: juju.ubuntu.com</a>
16 </li>
17 <li>
18 <a href="http://juju.ubuntu.com/docs"
19 target="_blank">Read the documentation</a>
20 </li>
21 <li>
22 <a href="https://www.surveymonkey.com/s/jujugui"
23 target="_blank">Take the survey</a>
24 </li>
25 <li class="landscape-url hidden">
26 <a href="">Landscape</a>
27 </li>
28 </ul>
29</span>
030
=== modified file 'app/templates/notifications.handlebars'
--- app/templates/notifications.handlebars 2013-10-24 18:02:16 +0000
+++ app/templates/notifications.handlebars 2013-11-13 18:41:54 +0000
@@ -1,25 +1,29 @@
1<span class="{{open}}">1<a href="" class="menu-link">
2 <a href="" id="notify-indicator" data-target="notify-list">2 <span id="notify-indicator">{{ count }}</span>
3 {{count}}3 Notifications
4 </a>4 <span class="expand">
5 <span id="notify-list" class="dropdown">5 <i class="sprite chevron_down more"></i>
6 <h3>6 <i class="sprite chevron_up less"></i>
7 {{count}} notifications7 </span>
8 </h3>8</a>
9 <ul>9<span class="dropdown">
10 {{#notifications}}10 <header>
11 <li id="{{clientId}}" class="notice">11 {{count}} notifications
12 <div>12 </header>
13 <h4>{{title}}</h4>13 {{#if notifications}}
14 <div>14 <ul>
15 {{message}}15 {{#notifications}}
16 </div>16 <li id="{{clientId}}" class="notice">
17 <small data-timestamp="{{timestamp}}"17 <h4>{{title}}</h4>
18 class="timestamp">{{humanizeTime timestamp}}</small>18 {{message}}
19 </div>19 <small data-timestamp="{{timestamp}}">
20 </li>20 {{humanizeTime timestamp}}
21 {{/notifications}}21 </small>
22 </ul>22 </li>
23 </span>23 {{/notifications}}
24 Notifications24 </ul>
25 {{else}}
26 <p>No notifications</p>
27 {{/if}}
28 <footer></footer>
25</span>29</span>
2630
=== modified file 'app/templates/onboarding.handlebars'
--- app/templates/onboarding.handlebars 2013-10-23 18:09:52 +0000
+++ app/templates/onboarding.handlebars 2013-11-13 18:41:54 +0000
@@ -5,7 +5,7 @@
5 </div>5 </div>
6 <div id="onboarding-screen-mask"></div>6 <div id="onboarding-screen-mask"></div>
7 <div id="onboarding-message">7 <div id="onboarding-message">
8 <a class="onboarding-cross sprite close-inspector-normal" href="" ></a>8 <button class="onboarding-cross sprite close-inspector-normal" href="" ></button>
9 <div class="panel panel-0">9 <div class="panel panel-0">
10 <h3 class="header type3">Welcome to Juju</h3>10 <h3 class="header type3">Welcome to Juju</h3>
11 <p class="text type11">Use Juju to quickly create, configure and deploy your application architectures to public clouds like EC2, Azure and HP, any OpenStack cloud and even your own Ubuntu based laptop with Charms.</p>11 <p class="text type11">Use Juju to quickly create, configure and deploy your application architectures to public clouds like EC2, Azure and HP, any OpenStack cloud and even your own Ubuntu based laptop with Charms.</p>
1212
=== modified file 'app/templates/overview.handlebars'
--- app/templates/overview.handlebars 2013-10-18 16:47:34 +0000
+++ app/templates/overview.handlebars 2013-11-13 18:41:54 +0000
@@ -22,10 +22,6 @@
22 <div class="menu-title">Select relation type:</div>22 <div class="menu-title">Select relation type:</div>
23 <ul/>23 <ul/>
24 </div>24 </div>
25 <div id="feedback-box">
26 <a target="_blank"
27 href="https://www.surveymonkey.com/s/jujugui">Feedback</a>
28 </div>
29 {{> right-sidebar }}25 {{> right-sidebar }}
30 </div>26 </div>
31 <div id="rmrelation-modal-panel"></div>27 <div id="rmrelation-modal-panel"></div>
3228
=== added file 'app/views/help-dropdown.js'
--- app/views/help-dropdown.js 1970-01-01 00:00:00 +0000
+++ app/views/help-dropdown.js 2013-11-13 18:41:54 +0000
@@ -0,0 +1,113 @@
1/*
2This file is part of the Juju GUI, which lets users view and manage Juju
3environments within a graphical interface (https://launchpad.net/juju-gui).
4Copyright (C) 2012-2013 Canonical Ltd.
5
6This program is free software: you can redistribute it and/or modify it under
7the terms of the GNU Affero General Public License version 3, as published by
8the Free Software Foundation.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
12SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
13General Public License for more details.
14
15You should have received a copy of the GNU Affero General Public License along
16with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19'use strict';
20
21/**
22 * Provide the help dropdown view.
23 *
24 * @module views
25 */
26
27YUI.add('help-dropdown', function(Y) {
28
29 var views = Y.namespace('juju.views'),
30 widgets = Y.namespace('juju.widgets'),
31 Templates = views.Templates;
32
33 /**
34 * The view associated with the help dropdown.
35 *
36 * @class HelpDropdownView
37 */
38 var HelpDropdownView = Y.Base.create('HelpDropdownView', Y.View,
39 [
40 Y.juju.Dropdown,
41 Y.Event.EventTracker
42 ], {
43 template: Templates['help-dropdown'],
44
45 events: {
46 '.start-onboarding': {
47 click: '_startOnboarding'
48 }
49 },
50
51 /**
52 * Start the onboarding tutorial.
53 *
54 * @method _startOnboarding
55 * @param {Event} ev the click event from the control.
56 * @private
57 */
58 _startOnboarding: function(ev) {
59 ev.halt();
60 // Added by the view-dropdown-extension.js
61 this.__close(); // Closes itself
62 // Because we need the app to be in sidebar mode when
63 // the user views the onboarding we navigate to it.
64 // Once fullscreen is removed we can interact with
65 // onboarding here instead of in browser.js
66 localStorage.setItem('force-onboarding', true);
67 this.fire('navigate', { url: '/sidebar' });
68 },
69
70 /**
71 * Show the Landscape URL if available.
72 *
73 * @method _displayLandscapeURL
74 * @private
75 */
76 _displayLandscapeURL: function() {
77 var env = this.get('env'),
78 url = this.get('container').one('.landscape-url'),
79 baseLandscapeURL = views.utils.getLandscapeURL(env);
80
81 if (baseLandscapeURL) {
82 url.one('a').setAttribute('href', baseLandscapeURL);
83 url.removeClass('hidden');
84 }
85 },
86
87 /**
88 * Sets up the DOM nodes and renders them to the DOM.
89 *
90 * @method render
91 */
92 render: function() {
93 var container = this.get('container');
94 container.setHTML(this.template());
95 this._displayLandscapeURL();
96 // Added by the view-dropdown-extension.js
97 this._addDropdownFunc();
98 return this;
99 }
100 });
101
102 views.HelpDropdownView = HelpDropdownView;
103
104}, '0.1.0', {
105 requires: [
106 'view',
107 'juju-view-utils',
108 'event-tracker',
109 'node',
110 'handlebars',
111 'view-dropdown-extension'
112 ]
113});
0114
=== modified file 'app/views/notifications.js'
--- app/views/notifications.js 2013-11-07 21:10:06 +0000
+++ app/views/notifications.js 2013-11-13 18:41:54 +0000
@@ -90,38 +90,6 @@
90 },90 },
9191
92 /**92 /**
93 * Event handler for clicking the notification icon.
94 *
95 * @method notifyToggle
96 */
97 notifyToggle: function(evt) {
98 evt.halt();
99 var container = this.get('container'),
100 notifications = this.get('notifications'),
101 target = evt.target.getAttribute('data-target'),
102 el = container.one('#' + target),
103 parent = el.ancestor();
104
105 if (notifications.size() === 0) {
106 return;
107 }
108
109 if (parent && parent.hasClass('open')) {
110 el.hide(true);
111 }
112 else {
113 el.show(true);
114 }
115
116 if (parent) {
117 parent.toggleClass('open');
118 }
119
120 el.toggleClass('active');
121
122 },
123
124 /**
125 * Select/click on a notice. Currently this just removes it from the93 * Select/click on a notice. Currently this just removes it from the
126 * model_list.94 * model_list.
127 *95 *
@@ -230,7 +198,11 @@
230 * @class NotificationsView198 * @class NotificationsView
231 */199 */
232 var NotificationsView = Y.Base.create('NotificationsView',200 var NotificationsView = Y.Base.create('NotificationsView',
233 NotificationsBaseView, [], {201 NotificationsBaseView,
202 [
203 Y.Event.EventTracker,
204 Y.juju.Dropdown
205 ], {
234 template: Templates.notifications,206 template: Templates.notifications,
235207
236 /*208 /*
@@ -244,12 +216,6 @@
244 seen: false216 seen: false
245 },217 },
246218
247 events: {
248 '#notify-indicator': {
249 click: 'notifyToggle'
250 }
251 },
252
253 /**219 /**
254 * @method getShowable220 * @method getShowable
255 */221 */
@@ -262,30 +228,15 @@
262 });228 });
263 },229 },
264230
265 close: function() {231 /**
266 var container = this.get('container');232 Renders the notification view and the dropdown widget.
267 if (!container) {233
268 return;234 @method render
269 }235 */
270
271 var indicator = container.one('#notify-indicator'),
272 list = container.one('#notify-list');
273
274 if (!indicator) {
275 return;
276 }
277 var parent = indicator.ancestor();
278
279 if (parent && parent.hasClass('open')) {
280 indicator.ancestor().removeClass('open');
281 list.hide();
282 indicator.removeClass('active');
283 }
284 },
285
286 render: function() {236 render: function() {
287 NotificationsView.superclass.render.apply(this, arguments);237 NotificationsView.superclass.render.apply(this, arguments);
288 this.get('container').on('clickoutside', this.close, this);238 // Added by the view-dropdown-extension.js
239 this._addDropdownFunc();
289 return this;240 return this;
290 }241 }
291242
@@ -298,6 +249,8 @@
298 'juju-view-utils',249 'juju-view-utils',
299 'node',250 'node',
300 'handlebars',251 'handlebars',
301 'notifier'252 'notifier',
253 'view-dropdown-extension',
254 'event-tracker'
302 ]255 ]
303});256});
304257
=== modified file 'app/views/onboarding.js'
--- app/views/onboarding.js 2013-10-21 23:05:08 +0000
+++ app/views/onboarding.js 2013-11-13 18:41:54 +0000
@@ -72,6 +72,7 @@
72 var container = this.get('container');72 var container = this.get('container');
73 container.hide();73 container.hide();
74 Y.one('#environment-help').removeClass('hidden');74 Y.one('#environment-help').removeClass('hidden');
75 localStorage.setItem('force-onboarding', '');
75 },76 },
7677
77 /**78 /**
@@ -182,6 +183,18 @@
182 },183 },
183184
184 /**185 /**
186 Sets the onboarding index back to 0, and the localstorage onboarding
187 flag to undefined.
188
189 @method reset
190 */
191 reset: function() {
192 this.onboardingIndex = 0;
193 localStorage.setItem('onboarding', '');
194 this.get('container').empty();
195 },
196
197 /**
185 * Render the page.198 * Render the page.
186 *199 *
187 * Reveal the mask element, and show the onboarding window.200 * Reveal the mask element, and show the onboarding window.
188201
=== modified file 'bin/merge-files'
--- bin/merge-files 2013-11-07 15:49:57 +0000
+++ bin/merge-files 2013-11-13 18:41:54 +0000
@@ -89,6 +89,7 @@
89 'app/assets/javascripts/app-subapp-extension.js',89 'app/assets/javascripts/app-subapp-extension.js',
90 'app/assets/javascripts/app-cookies-extension.js',90 'app/assets/javascripts/app-cookies-extension.js',
91 'app/assets/javascripts/bundle-import-extension.js',91 'app/assets/javascripts/bundle-import-extension.js',
92 'app/assets/javascripts/view-dropdown-extension.js',
92 'app/assets/javascripts/d3-components.js',93 'app/assets/javascripts/d3-components.js',
93 'app/assets/javascripts/d3.min.js',94 'app/assets/javascripts/d3.min.js',
94 'app/assets/javascripts/d3.status.js',95 'app/assets/javascripts/d3.status.js',
9596
=== modified file 'lib/views/browser/onboarding.less'
--- lib/views/browser/onboarding.less 2013-10-29 02:29:58 +0000
+++ lib/views/browser/onboarding.less 2013-11-13 18:41:54 +0000
@@ -58,6 +58,11 @@
58 color: @inspector-text-color;58 color: @inspector-text-color;
59 }59 }
6060
61 button {
62 border: none;
63 padding: 0;
64 }
65
61 img {66 img {
62 position: absolute;67 position: absolute;
63 }68 }
6469
=== modified file 'lib/views/dropdown.less'
--- lib/views/dropdown.less 2013-10-29 03:07:12 +0000
+++ lib/views/dropdown.less 2013-11-13 18:41:54 +0000
@@ -1,62 +1,118 @@
1.dropdown {1.dropdown-menu {
2 .customize-scrollbar;2 position: relative;
3 display: none;3 display: block;
4 position: absolute;4 margin: -20px -20px 0 -20px;
5 z-index: 1000;5
6 top: @navbar-height;6 &.open {
7 left: 0;7 .menu-link {
8 width: 290px;8 background-color: #000;
9 background-color: #eee;9
10 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);10 .expand {
1111 .more {
12 &.active {12 display: none;
13 }
14 .less {
15 display: inline-block;
16 }
17 }
18 }
19 .dropdown {
20 display: block;
21 }
22 }
23 .menu-link {
24 .border-box;
13 display: block;25 display: block;
14 }26 height: @navbar-height;
15 a,27 padding: 20px 20px 0 20px;
16 li {28 color: #d7d3d0;
17 color: #333;29
18 }30 .expand {
19 h3 {31 margin-left: 5px;
20 padding: 11px 20px;32
21 background-color: #000;33 .less {
22 color: #f2f2e6;34 display: none;
23 font-size: 16px;35 }
24 font-weight: 300;36 }
25 }37 }
26 ul {38 .dropdown {
27 max-height: 500px;39 .customize-scrollbar;
28 overflow-y: auto;40 display: none;
2941 position: absolute;
42 z-index: 1000;
43 top: @navbar-height;
44 left: 0;
45 width: 290px;
46 background-color: #eee;
47 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
48
49 &.right {
50 left: auto;
51 right: 0;
52 text-align: right;
53 }
54 &.narrow {
55 width: 230px;
56 }
57 a,
58 p,
30 li {59 li {
31 border-top: 1px solid #efefef;60 color: @text-colour;
32 border-bottom: 1px solid #e2e2e2;61 }
62 p {
63 padding: 11px 20px;
64 }
65 header,
66 footer {
67 background-color: #000;
68 }
69 header {
70 padding: 11px 20px;
71 color: #f2f2e6;
72 font-size: 16px;
73 font-weight: 300;
74 }
75 footer {
33 padding: 20px;76 padding: 20px;
3477 border-radius: 0 0 @border-radius @border-radius;
35 &:first-child {
36 border-top: none;
37 }
38 &:last-child {
39 border-bottom: none;
40 }
41 }78 }
42 // Notification items79 ul {
43 .notice {80 max-height: 500px;
44 h4 {81 overflow-y: auto;
45 font-weight: normal;82
46 margin-bottom: 10px;83 li {
47 }84 border-top: 1px solid #efefef;
48 small {85 border-bottom: 1px solid #e2e2e2;
49 display: block;86
50 margin-top: 5px;87 &:first-child {
51 font-size: 10px;88 border-top: none;
52 color: #d0d0d0;89 }
53 }90 &:last-child {
54 .error {91 border-bottom: none;
55 background-color: rgba(255, 0, 0, 0.1);92 }
93 a {
94 display: block;
95 padding: 15px 20px;
96
97 &:hover {
98 background-color: #e2e2e2;
99 }
100 }
101 }
102 // Notification items
103 .notice {
104 padding: 20px;
105
106 h4 {
107 margin-bottom: 10px;
108 }
109 small {
110 display: block;
111 margin-top: 5px;
112 font-size: 11px;
113 color: #aaa;
114 }
56 }115 }
57 }116 }
58 }117 }
59}118}
60.open .dropdown {
61 display: block;
62}
63119
=== modified file 'lib/views/stylesheet.less'
--- lib/views/stylesheet.less 2013-11-07 15:49:57 +0000
+++ lib/views/stylesheet.less 2013-11-13 18:41:54 +0000
@@ -175,16 +175,13 @@
175 */175 */
176.navbar {176.navbar {
177 min-width: 800px;177 min-width: 800px;
178 // Need to subtract the bottom-border-height.
179 height: @navbar-height;178 height: @navbar-height;
180 margin: -@navbar-height 0 0 0;179 margin: -@navbar-height 0 0 0;
181 background-color: #221e1b;180 background-color: #221e1b;
182181
183 &,182 &,
184 a {183 & > ul > li > a {
185 color: #d7d3d0;184 color: #d7d3d0;
186 font-size: 14px;
187 font-weight: 300;
188 }185 }
189186
190 ul {187 ul {
@@ -277,24 +274,11 @@
277 }274 }
278 &.notifications-nav {275 &.notifications-nav {
279 position: relative;276 position: relative;
280 padding: 0;277
281278 #notify-indicator {
282 #notifications {279 .button;
283 & > span {280 margin: -5px 9px 0 0;
284 .border-box;281 padding: 6px 12px;
285 display: block;
286 height: @navbar-height;
287 padding: 15px 20px 0 20px;
288
289 &.open {
290 background-color: #000;
291 }
292 #notify-indicator {
293 .button;
294 margin: 0 9px 0 0;
295 padding: 6px 12px;
296 }
297 }
298 }282 }
299 }283 }
300 }284 }
@@ -314,18 +298,6 @@
314 background-color: #1f1b18;298 background-color: #1f1b18;
315 }299 }
316 }300 }
317 .help-dropdown {
318 display: none;
319 position: relative;
320
321 .expand {
322 margin-left: 5px;
323
324 .hidden {
325 display: none;
326 }
327 }
328 }
329 }301 }
330}302}
331#content {303#content {
@@ -717,41 +689,6 @@
717}689}
718690
719/*691/*
720 * Feedback box
721 * Appears as a tab on the side of the canvas.
722 */
723#feedback-box {
724 position: absolute;
725 right: -40px;
726 bottom: 100px;
727 /* Up the z-index so the feedback box will overlay the zoom slider as it
728 * expands when hovered over */
729 z-index: 10;
730
731 a {
732 color: #fff;
733 background-color: @charm-panel-orange;
734 display: block;
735 line-height: 30px;
736 height: 40px;
737 font-weight: 500;
738 font-size: 16px;
739 padding: 0 10px;
740 margin-right: 3px;
741 -webkit-transition: all 0.15s ease-in-out;
742 -moz-transition: all 0.15s ease-in-out;
743 transition: all 0.15s ease-in-out;
744 .rotate(-90deg);
745
746 &:hover {
747 text-decoration: none;
748 background-color: #df6920;
749 margin-right: 13px;
750 }
751 }
752}
753
754/*
755 * Canvas zoom control692 * Canvas zoom control
756 */693 */
757.zoom-controls {694.zoom-controls {
758695
=== modified file 'test/index.html'
--- test/index.html 2013-10-31 14:16:29 +0000
+++ test/index.html 2013-11-13 18:41:54 +0000
@@ -70,6 +70,7 @@
70 <script src="test_databinding.js"></script>70 <script src="test_databinding.js"></script>
71 <script src="test_d3_components.js"></script>71 <script src="test_d3_components.js"></script>
72 <script src="test_d3_status.js"></script>72 <script src="test_d3_status.js"></script>
73 <script src="test_dropdown_extension.js"></script>
73 <script src="test_endpoints.js"></script>74 <script src="test_endpoints.js"></script>
74 <script src="test_env.js"></script>75 <script src="test_env.js"></script>
75 <script src="test_env_go.js"></script>76 <script src="test_env_go.js"></script>
@@ -79,6 +80,7 @@
79 <script src="test_fakebackend.js"></script>80 <script src="test_fakebackend.js"></script>
80 <script src="test_filter_widget.js"></script>81 <script src="test_filter_widget.js"></script>
81 <script src="test_ghost_inspector.js"></script>82 <script src="test_ghost_inspector.js"></script>
83 <script src="test_help_dropdown.js"></script>
82 <script src="test_inspector_charm.js"></script>84 <script src="test_inspector_charm.js"></script>
83 <script src="test_inspector_constraints.js"></script>85 <script src="test_inspector_constraints.js"></script>
84 <script src="test_inspector_overview.js"></script>86 <script src="test_inspector_overview.js"></script>
8587
=== modified file 'test/test_browser_app.js'
--- test/test_browser_app.js 2013-11-05 18:10:05 +0000
+++ test/test_browser_app.js 2013-11-13 18:41:54 +0000
@@ -1324,6 +1324,23 @@
1324 assert.deepEqual(hits, expected);1324 assert.deepEqual(hits, expected);
1325 });1325 });
13261326
1327 it('onboarding is rendered with force-onboarding query', function(done) {
1328 var req = {
1329 path: '/sidebar'
1330 };
1331
1332 localStorage.setItem('force-onboarding', true);
1333
1334 browser.renderOnboarding = function(force) {
1335 assert.equal(force, 'true');
1336 assert.equal(localStorage.getItem('force-onboarding'), '');
1337 assert.deepEqual(hits.sidebar, true);
1338 done();
1339 };
1340
1341 browser.routeView(req, undefined, function() {});
1342 });
1343
1327 it('/minimized dispatches correctly', function() {1344 it('/minimized dispatches correctly', function() {
1328 var req = {1345 var req = {
1329 path: '/minimized',1346 path: '/minimized',
13301347
=== added file 'test/test_dropdown_extension.js'
--- test/test_dropdown_extension.js 1970-01-01 00:00:00 +0000
+++ test/test_dropdown_extension.js 2013-11-13 18:41:54 +0000
@@ -0,0 +1,80 @@
1/*
2This file is part of the Juju GUI, which lets users view and manage Juju
3environments within a graphical interface (https://launchpad.net/juju-gui).
4Copyright (C) 2012-2013 Canonical Ltd.
5
6This program is free software: you can redistribute it and/or modify it under
7the terms of the GNU Affero General Public License version 3, as published by
8the Free Software Foundation.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
12SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
13General Public License for more details.
14
15You should have received a copy of the GNU Affero General Public License along
16with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19'use strict';
20
21
22describe('dropdown view extension', function() {
23 var Y, container, view, View;
24
25 before(function(done) {
26 Y = YUI(GlobalConfig).use(['view-dropdown-extension',
27 'juju-tests-utils',
28 'event-simulate',
29 'node-event-simulate',
30 'node'], function(Y) {
31
32 View = Y.Base.create('dropdown', Y.View, [
33 Y.juju.Dropdown,
34 Y.Event.EventTracker
35 ], {
36 template: '<a href="" class="menu-link"></a>' +
37 '<div class="dropdown"></div>',
38
39 render: function() {
40 this.get('container').setHTML(this.template);
41 this._addDropdownFunc();
42 return this;
43 }
44 });
45 done();
46 });
47 });
48
49 beforeEach(function() {
50 container = Y.namespace('juju-tests.utils').makeContainer();
51 view = new View({ container: container }).render();
52 });
53
54 afterEach(function() {
55 view.destroy();
56 container.remove().destroy(true);
57 });
58
59 it('should add the dropdown-menu class to the views container', function() {
60 assert.isTrue(container.hasClass('dropdown-menu'));
61 });
62
63 it('should open when the primary link is clicked', function(done) {
64 var link = container.one('.menu-link');
65 link.after('click', function() {
66 assert.isTrue(container.hasClass('open'));
67 done();
68 });
69 link.simulate('click');
70 });
71
72 it('should close when clicking outside the view', function() {
73 container.one('.menu-link').simulate('click');
74 assert.isTrue(container.hasClass('open'));
75
76 Y.one('body').simulate('click');
77 assert.isFalse(container.hasClass('open'));
78 });
79
80});
081
=== added file 'test/test_help_dropdown.js'
--- test/test_help_dropdown.js 1970-01-01 00:00:00 +0000
+++ test/test_help_dropdown.js 2013-11-13 18:41:54 +0000
@@ -0,0 +1,97 @@
1/*
2This file is part of the Juju GUI, which lets users view and manage Juju
3environments within a graphical interface (https://launchpad.net/juju-gui).
4Copyright (C) 2012-2013 Canonical Ltd.
5
6This program is free software: you can redistribute it and/or modify it under
7the terms of the GNU Affero General Public License version 3, as published by
8the Free Software Foundation.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
12SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
13General Public License for more details.
14
15You should have received a copy of the GNU Affero General Public License along
16with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19'use strict';
20
21describe('help dropdown view', function() {
22
23 var db, envAnno, helpView, views, landscape, models, viewNode, Y;
24
25 before(function(done) {
26 Y = YUI(GlobalConfig).use(['node',
27 'juju-landscape',
28 'juju-models',
29 'juju-views',
30 'help-dropdown',
31 'juju-tests-utils'], function(Y) {
32
33 views = Y.namespace('juju.views');
34 models = Y.namespace('juju.models');
35
36 db = new models.Database();
37 landscape = new views.Landscape();
38 landscape.set('db', db);
39
40 done();
41 });
42 });
43
44 beforeEach(function() {
45 envAnno = db.environment.get('annotations');
46 viewNode = Y.namespace('juju-tests.utils').makeContainer('help-dropdown');
47 });
48
49 afterEach(function() {
50 viewNode.remove().destroy(true);
51 if (helpView) {
52 helpView.destroy();
53 }
54 });
55
56 it('renders the basic list', function() {
57 helpView = new views.HelpDropdownView({
58 container: viewNode,
59 env: db.environment
60 }).render();
61 // Landscape url should be hidden
62 var container = helpView.get('container');
63 assert.equal(
64 container.one('.landscape-url').getStyle('display'), 'none');
65 assert.equal(container.all('li').size(), 5);
66 });
67
68 it('should display the Landscape menu item', function() {
69 envAnno['landscape-url'] = 'http://landscape.example.com';
70 envAnno['landscape-computers'] = '/computers/criteria/environment:test';
71 new views.HelpDropdownView({
72 container: viewNode,
73 env: db.environment
74 }).render();
75
76 assert.equal(
77 viewNode.one('.landscape-url').getStyle('display'), 'list-item');
78 assert.equal(
79 viewNode.one('.landscape-url a').get('href'),
80 'http://landscape.example.com/computers/criteria/environment:test/');
81 });
82
83 it('can start the onboarding visualization', function(done) {
84 helpView = new views.HelpDropdownView({
85 container: viewNode,
86 env: db.environment
87 });
88 helpView.on('navigate', function(e) {
89 assert.equal(e.url, '/sidebar');
90 assert.equal(localStorage.getItem('force-onboarding'), 'true');
91 done();
92 });
93 helpView.render();
94 var ob = helpView.get('container').one('.start-onboarding');
95 ob.simulate('click');
96 });
97});
098
=== modified file 'test/test_notifications.js'
--- test/test_notifications.js 2013-10-29 23:10:25 +0000
+++ test/test_notifications.js 2013-11-13 18:41:54 +0000
@@ -159,7 +159,7 @@
159 nsRouter: nsRouter});159 nsRouter: nsRouter});
160 view.render();160 view.render();
161 // Verify the expected elements appear in the view161 // Verify the expected elements appear in the view
162 container.one('#notify-list').should.not.equal(undefined);162 container.one('.dropdown').should.not.equal(undefined);
163 container.destroy();163 container.destroy();
164 });164 });
165165
@@ -330,33 +330,6 @@
330 notice.get('message').should.equal('');330 notice.get('message').should.equal('');
331 });331 });
332332
333
334 it('should open on click and close on clickoutside', function(done) {
335 var container = Y.Node.create(
336 '<div id="test-container" style="display: none" class="container"/>'),
337 notifications = new models.NotificationList(),
338 env = juju.newEnvironment(),
339 view = new views.NotificationsView({
340 container: container,
341 notifications: notifications,
342 env: env,
343 nsRouter: nsRouter}).render(),
344 indicator;
345
346 Y.one('body').append(container);
347 notifications.add({title: 'testing', 'level': 'error'});
348 indicator = container.one('#notify-indicator');
349
350 indicator.simulate('click');
351 indicator.ancestor().hasClass('open').should.equal(true);
352
353 Y.one('body').simulate('click');
354 indicator.ancestor().hasClass('open').should.equal(false);
355
356 container.remove();
357 done();
358 });
359
360});333});
361334
362335
363336
=== modified file 'test/test_onboarding.js'
--- test/test_onboarding.js 2013-10-23 00:12:47 +0000
+++ test/test_onboarding.js 2013-11-13 18:41:54 +0000
@@ -158,6 +158,7 @@
158 onboard.closeHandler({halt: function() {}});158 onboard.closeHandler({halt: function() {}});
159 assert.equal(container.getComputedStyle('display'), 'none');159 assert.equal(container.getComputedStyle('display'), 'none');
160 assert.isFalse(env_help.hasClass('hidden'));160 assert.isFalse(env_help.hasClass('hidden'));
161 assert.equal(localStorage.getItem('force-onboarding'), '');
161 });162 });
162163
163 it('should not be shown if seen before', function() {164 it('should not be shown if seen before', function() {
@@ -171,5 +172,19 @@
171 assert.isTrue(background instanceof Y.Node);172 assert.isTrue(background instanceof Y.Node);
172 });173 });
173174
175 it('sets index to 0, clears out local storage on reset', function() {
176 var onboard = new OnboardingView({
177 container: container
178 }).render();
179 onboard.nextHandler({halt: function() {}});
180 assert.equal(onboard.onboardingIndex, 1);
181
182 localStorage.setItem('onboarding', true);
183
184 onboard.reset();
185 assert.equal(onboard.onboardingIndex, 0);
186 assert.equal(localStorage.getItem('onboarding'), '');
187 });
188
174 });189 });
175})();190})();
176191
=== modified file 'undocumented'
--- undocumented 2013-10-02 16:26:20 +0000
+++ undocumented 2013-11-13 18:41:54 +0000
@@ -71,7 +71,6 @@
71app/views/notifications.js:42 "initializer"71app/views/notifications.js:42 "initializer"
72app/views/notifications.js:286 "render"72app/views/notifications.js:286 "render"
73app/views/notifications.js:173 "render"73app/views/notifications.js:173 "render"
74app/views/notifications.js:265 "close"
75app/views/databinding.js:81 "keyfunc"74app/views/databinding.js:81 "keyfunc"
76app/views/topology/panzoom.js:91 "renderSlider"75app/views/topology/panzoom.js:91 "renderSlider"
77app/views/topology/panzoom.js:265 "renderedHandler"76app/views/topology/panzoom.js:265 "renderedHandler"

Subscribers

People subscribed via source and target branches