Merge lp:~rharding/juju-gui/qa-ant-onboarding into lp:juju-gui/experimental

Proposed by Richard Harding
Status: Merged
Merged at revision: 1140
Proposed branch: lp:~rharding/juju-gui/qa-ant-onboarding
Merge into: lp:juju-gui/experimental
Diff against target: 717 lines (+613/-0)
8 files modified
app/app.js (+26/-0)
app/index.html (+3/-0)
app/modules-debug.js (+4/-0)
app/templates/onboarding.handlebars (+33/-0)
app/views/onboarding.js (+210/-0)
lib/views/stylesheet.less (+172/-0)
test/index.html (+1/-0)
test/test_onboarding.js (+164/-0)
To merge this branch: bzr merge lp:~rharding/juju-gui/qa-ant-onboarding
Reviewer Review Type Date Requested Status
Juju GUI Hackers Pending
Review via email: mp+191208@code.launchpad.net

Description of the change

Add support for an initial onboarding walkthrough

- Submitting for Ant
- Under the feature flag :flags:/onboard

https://codereview.appspot.com/14700043/

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

Reviewers: mp+191208_code.launchpad.net,

Message:
Please take a look.

Description:
Add support for an initial onboarding walkthrough

- Submitting for Ant

https://code.launchpad.net/~rharding/juju-gui/qa-ant-onboarding/+merge/191208

(do not edit description out of merge proposal)

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

Affected files (+447, --6 lines):
   A [revision details]
   M app/app.js
   A app/assets/images/close-inspector-click.png
   A app/assets/images/close-inspector-hover.png
   A app/assets/images/close-inspector-normal.png
   A app/assets/images/non-sprites/onboarding/2-service-blocks.png
   A app/assets/images/non-sprites/onboarding/3-inspector.png
   A app/assets/images/non-sprites/onboarding/3-service-block.png
   M app/index.html
   M app/modules-debug.js
   M app/store/env/base.js
   A app/templates/onboarding.handlebars
   A app/views/onboarding.js
   M lib/views/stylesheet.less

Revision history for this message
Richard Harding (rharding) wrote :
Download full text (4.2 KiB)

Feedback below.

https://codereview.appspot.com/14700043/diff/1/app/app.js
File app/app.js (right):

https://codereview.appspot.com/14700043/diff/1/app/app.js#newcode1095
app/app.js:1095:
remove this blank line

https://codereview.appspot.com/14700043/diff/1/app/app.js#newcode1129
app/app.js:1129: initialise_onboarding: function() {
initialize (I know it's a US/UK english thing, but initialize is used
throughout the app already)

https://codereview.appspot.com/14700043/diff/1/app/app.js#newcode1131
app/app.js:1131: if (!this._onboarding) {
this is where I'd add the feature flag check.

if (!this._onboarding && window.flags.onboard) { ...

https://codereview.appspot.com/14700043/diff/1/app/app.js#newcode1132
app/app.js:1132: // Need to check onboarding exists due to the double
dispatch bug.
this comment kind of goes above this line where the if is.

https://codereview.appspot.com/14700043/diff/1/app/app.js#newcode1140
app/app.js:1140: this._onboarding.close();
why do we need to close here? If you hit the root url, and we render.
You close it with the button/control in the UI. If you're not at the /
url then we never show this and there's nothing to close?

https://codereview.appspot.com/14700043/diff/1/app/store/env/base.js
File app/store/env/base.js (right):

https://codereview.appspot.com/14700043/diff/1/app/store/env/base.js#newcode170
app/store/env/base.js:170: 'onboardDismissed': {value: false},
you had mentioned that it's not saving this value. This comes in to
where I'd create a valueFn that could check against your storage
location (session storage or localstorage) and pull the value out of
there. If it's not defined, then you show, else you don't show. The
render method would do a check when you hit it.

https://codereview.appspot.com/14700043/diff/1/app/views/onboarding.js
File app/views/onboarding.js (right):

https://codereview.appspot.com/14700043/diff/1/app/views/onboarding.js#newcode31
app/views/onboarding.js:31: var onboardingIndex = 0;
this is specific to the current view. I think this should be an
attribute created or set on initialize, or maybe another ATTR.

https://codereview.appspot.com/14700043/diff/1/app/views/onboarding.js#newcode53
app/views/onboarding.js:53: '.onboarding-cross': {
can this not be done with css using :hover state?

https://codereview.appspot.com/14700043/diff/1/app/views/onboarding.js#newcode71
app/views/onboarding.js:71: this.close();
is there any way to get back to the onboarding dialog after it's been
closed? Could this actually do a this.destroy() and remove itself from
the dom as well?

https://codereview.appspot.com/14700043/diff/1/app/views/onboarding.js#newcode94
app/views/onboarding.js:94: this.onboardingIndex = 0;
you set this.onboardingIndex here, but you use the unattached version
elsewhere?

https://codereview.appspot.com/14700043/diff/1/app/views/onboarding.js#newcode110
app/views/onboarding.js:110: onboardingIndex = onboardingIndex + 1;
this.onboardingIndex

https://codereview.appspot.com/14700043/diff/1/app/views/onboarding.js#newcode135
app/views/onboarding.js:135: crossHandler: function(ev) {
yea, I'd think this whole function could go away if the css was updated
per https://develop...

Read more...

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

QA Notes:

I didn't get the mask until I hit "Get Started" it seems like it would
mask to start out with?

Once when I got to the second step did it mask over the sidebar?

https://codereview.appspot.com/14700043/

1128. By Richard Harding

Fix the reference to the class

Revision history for this message
Anthony Dillon (ya-bo-ng) wrote :
Download full text (3.1 KiB)

Comments back to Rick's review. Any uncommented are complete.

https://codereview.appspot.com/14700043/diff/1/app/app.js
File app/app.js (right):

https://codereview.appspot.com/14700043/diff/1/app/app.js#newcode1140
app/app.js:1140: this._onboarding.close();
On 2013/10/15 14:55:34, rharding wrote:
> why do we need to close here? If you hit the root url, and we render.
You close
> it with the button/control in the UI. If you're not at the / url then
we never
> show this and there's nothing to close?

This is used when the user use's the browsers navigation buttons to jump
form build and browse.

https://codereview.appspot.com/14700043/diff/1/app/store/env/base.js
File app/store/env/base.js (right):

https://codereview.appspot.com/14700043/diff/1/app/store/env/base.js#newcode170
app/store/env/base.js:170: 'onboardDismissed': {value: false},
On 2013/10/15 14:55:34, rharding wrote:
> you had mentioned that it's not saving this value. This comes in to
where I'd
> create a valueFn that could check against your storage location
(session storage
> or localstorage) and pull the value out of there. If it's not defined,
then you
> show, else you don't show. The render method would do a check when you
hit it.

I created this value in the storage for this purpose but did not manage
to set or get it from app.js when rendering.

https://codereview.appspot.com/14700043/diff/1/app/views/onboarding.js
File app/views/onboarding.js (right):

https://codereview.appspot.com/14700043/diff/1/app/views/onboarding.js#newcode53
app/views/onboarding.js:53: '.onboarding-cross': {
On 2013/10/15 14:55:34, rharding wrote:
> can this not be done with css using :hover state?

These events are used to update the spirited background image, therefore
need to update the class on the element.

https://codereview.appspot.com/14700043/diff/1/app/views/onboarding.js#newcode71
app/views/onboarding.js:71: this.close();
On 2013/10/15 14:55:34, rharding wrote:
> is there any way to get back to the onboarding dialog after it's been
closed?
> Could this actually do a this.destroy() and remove itself from the dom
as well?

There is going to be a drop down in the header that contains an option
to display the onboarding message again.

https://codereview.appspot.com/14700043/diff/1/app/views/onboarding.js#newcode135
app/views/onboarding.js:135: crossHandler: function(ev) {
On 2013/10/15 14:55:34, rharding wrote:
> yea, I'd think this whole function could go away if the css was
updated per
> https://developer.mozilla.org/en-US/docs/Web/CSS/:hover

Required for sprite updates.

https://codereview.appspot.com/14700043/diff/1/lib/views/stylesheet.less
File lib/views/stylesheet.less (right):

https://codereview.appspot.com/14700043/diff/1/lib/views/stylesheet.less#newcode2043
lib/views/stylesheet.less:2043: &.state-1 {
On 2013/10/15 14:55:34, rharding wrote:
> this seems like it could be done using a .active flag or something.
Where one of
> the divs is marked .active and .active picks up things like display
block and
> sets background color?

The reason I did it this way is because the different states control the
screen-mask which I outside the panels.

https://codereview.appspot.com/14700043/...

Read more...

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

Comment

https://codereview.appspot.com/14700043/diff/1/app/app.js
File app/app.js (right):

https://codereview.appspot.com/14700043/diff/1/app/app.js#newcode1140
app/app.js:1140: this._onboarding.close();
On 2013/10/15 16:13:05, Ant wrote:
> On 2013/10/15 14:55:34, rharding wrote:
> > why do we need to close here? If you hit the root url, and we
render. You
> close
> > it with the button/control in the UI. If you're not at the / url
then we never
> > show this and there's nothing to close?

> This is used when the user use's the browsers navigation buttons to
jump form
> build and browse.

When they go from browse to build though the url changes and will no
longer be /. So I think it's safe to leave this out.

https://codereview.appspot.com/14700043/

Revision history for this message
Anthony Dillon (ya-bo-ng) wrote :

https://codereview.appspot.com/14700043/diff/1/app/app.js
File app/app.js (right):

https://codereview.appspot.com/14700043/diff/1/app/app.js#newcode1140
app/app.js:1140: this._onboarding.close();
On 2013/10/15 16:27:00, rharding wrote:
> On 2013/10/15 16:13:05, Ant wrote:
> > On 2013/10/15 14:55:34, rharding wrote:
> > > why do we need to close here? If you hit the root url, and we
render. You
> > close
> > > it with the button/control in the UI. If you're not at the / url
then we
> never
> > > show this and there's nothing to close?
> >
> > This is used when the user use's the browsers navigation buttons to
jump form
> > build and browse.

> When they go from browse to build though the url changes and will no
longer be
> /. So I think it's safe to leave this out.

Ok, taking it out.

https://codereview.appspot.com/14700043/

Revision history for this message
Anthony Dillon (ya-bo-ng) wrote :

On 2013/10/15 15:00:22, rharding wrote:
> QA Notes:

> I didn't get the mask until I hit "Get Started" it seems like it would
mask to
> start out with?

> Once when I got to the second step did it mask over the sidebar?

That is a UX/design decision. It is the behaviour I was given to
implement. Testing may prove you right :)

https://codereview.appspot.com/14700043/

1129. By Richard Harding

Sync with upstream

1130. By Richard Harding

Lint

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

Sync

1132. By Richard Harding

Adjust

1133. By Richard Harding

Sync lint changes

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

LGTM, couple of small tweaks I think.

https://codereview.appspot.com/14700043/diff/15001/app/app.js
File app/app.js (right):

https://codereview.appspot.com/14700043/diff/15001/app/app.js#newcode84
app/app.js:84: onboarding: {
we manually run the view so this doesn't need to be here.

https://codereview.appspot.com/14700043/diff/15001/app/store/env/base.js
File app/store/env/base.js (right):

https://codereview.appspot.com/14700043/diff/15001/app/store/env/base.js#newcode170
app/store/env/base.js:170: 'onboardDismissed': {value: false},
is this used? If not can we get rid of this as well?

https://codereview.appspot.com/14700043/diff/15001/app/views/onboarding.js
File app/views/onboarding.js (right):

https://codereview.appspot.com/14700043/diff/15001/app/views/onboarding.js#newcode175
app/views/onboarding.js:175: this.onboardingIndex + 1, this.stateCount);
this should just be this.states.length

https://codereview.appspot.com/14700043/diff/15001/app/views/onboarding.js#newcode204
app/views/onboarding.js:204: this.stateCount = this.states.length - 1;
I'd just move this up to the incrementIndex since you don't need/use it
elsewhere.

https://codereview.appspot.com/14700043/diff/15001/test/test_onboarding.js
File test/test_onboarding.js (right):

https://codereview.appspot.com/14700043/diff/15001/test/test_onboarding.js#newcode159
test/test_onboarding.js:159: onboard.closeHandler({halt: function()
{}});
What you can do here is to do a onboardingCross.simulate('click') and it
should fire the click event and it'll close.

https://codereview.appspot.com/14700043/

Revision history for this message
Gary Poster (gary) wrote :
Download full text (3.8 KiB)

LGTM if you change the route check code in app.js. I'll try to look up
the proper spelling and post it here in a few minutes. Everything else
is trivial and/or just suggestions or ideas.

https://codereview.appspot.com/14700043/diff/15001/app/app.js
File app/app.js (right):

https://codereview.appspot.com/14700043/diff/15001/app/app.js#newcode1132
app/app.js:1132: if (path === '/' || path === '/:flags:/onboard/') {
Technically, this should use the routing code to get the path in the
default namespace. I'll try to dig up how to do that later.

I say "technically" because we are interested in removing the namespace
code. We aren't doing that right now, though, so using the routing's
parsing code is the right thing to do.

https://codereview.appspot.com/14700043/diff/15001/app/store/env/base.js
File app/store/env/base.js (right):

https://codereview.appspot.com/14700043/diff/15001/app/store/env/base.js#newcode170
app/store/env/base.js:170: 'onboardDismissed': {value: false},
On 2013/10/16 17:01:11, rharding wrote:
> is this used? If not can we get rid of this as well?

Looks like it is part of a nascent plan to persist the flag, but I agree
that we ought to keep this out until/unless it's used.

https://codereview.appspot.com/14700043/diff/15001/app/views/onboarding.js
File app/views/onboarding.js (right):

https://codereview.appspot.com/14700043/diff/15001/app/views/onboarding.js#newcode72
app/views/onboarding.js:72: this.close();
I don't yet see the value of separating closeHandler and close. Even
for testing this doesn't seem like a huge win. OTOH, maybe I'm missing
something.

https://codereview.appspot.com/14700043/diff/15001/app/views/onboarding.js#newcode119
app/views/onboarding.js:119: * @method nextHandler
prevHandler

https://codereview.appspot.com/14700043/diff/15001/app/views/onboarding.js#newcode136
app/views/onboarding.js:136: crossHandler: function(ev) {
(1) this is also registered for mouseup. Why?
(2) Other than the blasted documentation blather :-D, this feels like it
would be cleaner as separate methods, one for each event. That's a
suggestion: take it or leave it.
(3) .replaceClass(..., ...) could make each type into single calls.
(4) I hope the close-inspector-click style wins over the -hover or
-normal styles, or that they get along somehow. I'll assume they do.

https://codereview.appspot.com/14700043/diff/15001/app/views/onboarding.js#newcode175
app/views/onboarding.js:175: this.onboardingIndex + 1, this.stateCount);
On 2013/10/16 17:01:11, rharding wrote:
> this should just be this.states.length

you mean, "this.stateCount" should be "this.states.length - 1". Sounds
good to me.

https://codereview.appspot.com/14700043/diff/15001/app/views/onboarding.js#newcode204
app/views/onboarding.js:204: this.stateCount = this.states.length - 1;
On 2013/10/16 17:01:11, rharding wrote:
> I'd just move this up to the incrementIndex since you don't need/use
it
> elsewhere.

+1

https://codereview.appspot.com/14700043/diff/15001/test/test_onboarding.js
File test/test_onboarding.js (right):

https://codereview.appspot.com/14700043/diff/15001/test/test_onboarding.js#newcode74
test/test_onboarding.js:74: assert.equal(onboard.onbo...

Read more...

Revision history for this message
Gary Poster (gary) wrote :

QA not ok, but if you apply the following patch and write associated
tests, it will be good.

http://paste.ubuntu.com/6247161/

This makes the flag handling much less fragile
(http://localhost:8888/sidebar/:flags:/charmworldv3/onboard/ shows
onboarding as it should, for instance) and disables onboarding for the
fullscreen view, where it will be broken. Please merge this and then
write a few associated tests.

Thank you!

https://codereview.appspot.com/14700043/

1134. By Richard Harding

Sync with trunk

1135. By Richard Harding

Sync with Ant

Revision history for this message
Richard Harding (rharding) wrote :
Revision history for this message
Anthony Dillon (ya-bo-ng) wrote :

https://codereview.appspot.com/14700043/diff/15001/app/views/onboarding.js
File app/views/onboarding.js (right):

https://codereview.appspot.com/14700043/diff/15001/app/views/onboarding.js#newcode136
app/views/onboarding.js:136: crossHandler: function(ev) {
On 2013/10/16 17:52:32, gary.poster wrote:
> (1) this is also registered for mouseup. Why?
> (2) Other than the blasted documentation blather :-D, this feels like
it would
> be cleaner as separate methods, one for each event. That's a
suggestion: take
> it or leave it.
> (3) .replaceClass(..., ...) could make each type into single calls.
> (4) I hope the close-inspector-click style wins over the -hover or
-normal
> styles, or that they get along somehow. I'll assume they do.

1. The mouse up event calls closeHandler
2. I'll leave this for now but happy to update if required
3. Brilliant, done.
4. The close-inspector-click displays a brighter cross.

https://codereview.appspot.com/14700043/

1136. By Richard Harding

Add quick lint

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

*** Submitted:

Add support for an initial onboarding walkthrough

- Submitting for Ant
- Under the feature flag :flags:/onboard

R=Ant, gary.poster
CC=
https://codereview.appspot.com/14700043

https://codereview.appspot.com/14700043/

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-10-17 00:17:47 +0000
+++ app/app.js 2013-10-17 15:15:29 +0000
@@ -372,6 +372,7 @@
372 this.cookieHandler = null;372 this.cookieHandler = null;
373373
374 this.renderEnvironment = true;374 this.renderEnvironment = true;
375
375 // If this property has a value other than '/' then376 // If this property has a value other than '/' then
376 // navigate to it after logging in.377 // navigate to it after logging in.
377 this.redirectPath = '/';378 this.redirectPath = '/';
@@ -1109,13 +1110,37 @@
1109 */1110 */
1110 callback: function() {1111 callback: function() {
1111 this.views.environment.instance.rendered();1112 this.views.environment.instance.rendered();
1113 this.initializeOnboarding();
1112 },1114 },
1113 render: true1115 render: true
1114 });1116 });
1117
1115 next();1118 next();
1116 },1119 },
11171120
1118 /**1121 /**
1122 * Create a 'welcome' message walkthrough for new usersl.
1123 *
1124 * @method initialize_onboarding
1125 */
1126 initializeOnboarding: function() {
1127 var path = window.location.pathname;
1128 // Need to check onboarding exists due to the double dispatch bug.
1129 if (!this._onboarding && window.flags.onboard) {
1130 if (path === '/' || path === '/:flags:/onboard/') {
1131 var paths = this.nsRouter.parse(window.location.toString());
1132 path = paths.charmbrowser;
1133 if (path === '/sidebar/' ||
1134 (this.get('defaultViewmode') === 'sidebar' && path === '/')) {
1135 this._onboarding = new Y.juju.views.OnboardingView(
1136 {'container': '#onboarding'});
1137 this._onboarding.render();
1138 }
1139 }
1140 }
1141 },
1142
1143 /**
1119 * Object routing support1144 * Object routing support
1120 *1145 *
1121 * This utility helps map from model objects to routes1146 * This utility helps map from model objects to routes
@@ -1334,6 +1359,7 @@
1334 'juju-views',1359 'juju-views',
1335 'juju-view-environment',1360 'juju-view-environment',
1336 'juju-view-login',1361 'juju-view-login',
1362 'juju-view-onboarding',
1337 'juju-landscape',1363 'juju-landscape',
1338 'juju-websocket-logging',1364 'juju-websocket-logging',
1339 'io',1365 'io',
13401366
=== added file 'app/assets/images/close-inspector-click.png'
1341Binary files app/assets/images/close-inspector-click.png 1970-01-01 00:00:00 +0000 and app/assets/images/close-inspector-click.png 2013-10-17 15:15:29 +0000 differ1367Binary files app/assets/images/close-inspector-click.png 1970-01-01 00:00:00 +0000 and app/assets/images/close-inspector-click.png 2013-10-17 15:15:29 +0000 differ
=== added file 'app/assets/images/close-inspector-hover.png'
1342Binary files app/assets/images/close-inspector-hover.png 1970-01-01 00:00:00 +0000 and app/assets/images/close-inspector-hover.png 2013-10-17 15:15:29 +0000 differ1368Binary files app/assets/images/close-inspector-hover.png 1970-01-01 00:00:00 +0000 and app/assets/images/close-inspector-hover.png 2013-10-17 15:15:29 +0000 differ
=== added file 'app/assets/images/close-inspector-normal.png'
1343Binary files app/assets/images/close-inspector-normal.png 1970-01-01 00:00:00 +0000 and app/assets/images/close-inspector-normal.png 2013-10-17 15:15:29 +0000 differ1369Binary files app/assets/images/close-inspector-normal.png 1970-01-01 00:00:00 +0000 and app/assets/images/close-inspector-normal.png 2013-10-17 15:15:29 +0000 differ
=== added directory 'app/assets/images/non-sprites/onboarding'
=== added file 'app/assets/images/non-sprites/onboarding/2-service-blocks.png'
1344Binary files app/assets/images/non-sprites/onboarding/2-service-blocks.png 1970-01-01 00:00:00 +0000 and app/assets/images/non-sprites/onboarding/2-service-blocks.png 2013-10-17 15:15:29 +0000 differ1370Binary files app/assets/images/non-sprites/onboarding/2-service-blocks.png 1970-01-01 00:00:00 +0000 and app/assets/images/non-sprites/onboarding/2-service-blocks.png 2013-10-17 15:15:29 +0000 differ
=== added file 'app/assets/images/non-sprites/onboarding/3-inspector.png'
1345Binary files app/assets/images/non-sprites/onboarding/3-inspector.png 1970-01-01 00:00:00 +0000 and app/assets/images/non-sprites/onboarding/3-inspector.png 2013-10-17 15:15:29 +0000 differ1371Binary files app/assets/images/non-sprites/onboarding/3-inspector.png 1970-01-01 00:00:00 +0000 and app/assets/images/non-sprites/onboarding/3-inspector.png 2013-10-17 15:15:29 +0000 differ
=== added file 'app/assets/images/non-sprites/onboarding/3-service-block.png'
1346Binary files app/assets/images/non-sprites/onboarding/3-service-block.png 1970-01-01 00:00:00 +0000 and app/assets/images/non-sprites/onboarding/3-service-block.png 2013-10-17 15:15:29 +0000 differ1372Binary files app/assets/images/non-sprites/onboarding/3-service-block.png 1970-01-01 00:00:00 +0000 and app/assets/images/non-sprites/onboarding/3-service-block.png 2013-10-17 15:15:29 +0000 differ
=== modified file 'app/index.html'
--- app/index.html 2013-10-17 00:17:47 +0000
+++ app/index.html 2013-10-17 15:15:29 +0000
@@ -101,6 +101,9 @@
101 </div>101 </div>
102 </div>102 </div>
103 </div>103 </div>
104
105 <div id="onboarding"></div>
106
104 <div class="cookie-policy" style="display:none;">107 <div class="cookie-policy" style="display:none;">
105 <div class="wrapper">108 <div class="wrapper">
106 <a href="" class="link-cta">Close</a>109 <a href="" class="link-cta">Close</a>
107110
=== modified file 'app/modules-debug.js'
--- app/modules-debug.js 2013-10-02 16:26:20 +0000
+++ app/modules-debug.js 2013-10-17 15:15:29 +0000
@@ -249,6 +249,10 @@
249 fullpath: '/juju-ui/views/login.js'249 fullpath: '/juju-ui/views/login.js'
250 },250 },
251251
252 'juju-view-onboarding': {
253 fullpath: '/juju-ui/views/onboarding.js'
254 },
255
252 'juju-templates': {256 'juju-templates': {
253 fullpath: '/juju-ui/templates.js'257 fullpath: '/juju-ui/templates.js'
254 },258 },
255259
=== added file 'app/templates/onboarding.handlebars'
--- app/templates/onboarding.handlebars 1970-01-01 00:00:00 +0000
+++ app/templates/onboarding.handlebars 2013-10-17 15:15:29 +0000
@@ -0,0 +1,33 @@
1
2<div id="onboarding-background" class="state-0">
3 <div id="onboarding-screen-mask"></div>
4 <div id="onboarding-message">
5 <a class="onboarding-cross sprite close-inspector-normal" href="" ></a>
6 <div class="panel panel-0">
7 <h3 class="header type3">Welcome to Juju</h3>
8 <p class="text type11">Juju enables you to configure, manage, maintain, deploy and scale efficiently with best-practice Charms on any cloud or your own Ubuntu laptop.</p>
9 </div>
10 <div class="panel panel-1">
11 <h3 class="header type3">Build your environment</h3>
12 <p class="text type11">The Charm browser has hundreds of Charms allowing you to build complex services which can be visualised in Juju.</p>
13 <p class=" text type11">Drag them from the Charm browser onto your canvas to start building your environments.</p>
14 </div>
15 <div class="panel panel-2">
16 <h3 class="header type3">Connect services</h3>
17 <p class="text type11">Configure and deploy your services and connect them with intelligent relationship lines to build your environment.</p>
18 <img src="/juju-ui/assets/images/non-sprites/onboarding/2-service-blocks.png" class="service-blocks" />
19 </div>
20 <div class="panel panel-3">
21 <h3 class="header type3">Monitor and manage</h3>
22 <p class="text type11">The Juju GUI inspector offers comprehensive tools that give you ability to scale out, triage errors and update your services.</p>
23 <img src="/juju-ui/assets/images/non-sprites/onboarding/3-service-block.png" class="service-block" />
24 <img src="/juju-ui/assets/images/non-sprites/onboarding/3-inspector.png" class="inspector" />
25 </div>
26 <ul>
27 <li><a href="" class="onboarding-close">Get started</a></li>
28 <li><a href="" class="onboarding-start highlight">Quick tour of Juju</a></li>
29 <li><a href="" class="onboarding-next highlight">Next</a></li>
30 <li><a href="" class="onboarding-prev">Prev</a></li>
31 </ul>
32 </div>
33</div>
0\ No newline at end of file34\ No newline at end of file
135
=== added file 'app/views/onboarding.js'
--- app/views/onboarding.js 1970-01-01 00:00:00 +0000
+++ app/views/onboarding.js 2013-10-17 15:15:29 +0000
@@ -0,0 +1,210 @@
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 OnboardingView class.
23 *
24 * @module onboarding
25 * @submodule views.onboarding
26 */
27
28YUI.add('juju-view-onboarding', function(Y) {
29
30 var views = Y.namespace('juju.views');
31
32 /**
33 * The OnboardingView class.
34 *
35 * @class OnboardingView
36 */
37 views.OnboardingView = Y.Base.create('OnboardingView', Y.View, [], {
38 template: views.Templates.onboarding,
39 events: {
40 '.onboarding-close': {
41 click: 'closeHandler'
42 },
43 '.onboarding-start': {
44 click: 'nextHandler'
45 },
46 '.onboarding-next': {
47 click: 'nextHandler'
48 },
49 '.onboarding-prev': {
50 click: 'prevHandler'
51 },
52 '.onboarding-cross': {
53 mousedown: 'crossHandler',
54 mouseout: 'crossHandler',
55 mouseover: 'crossHandler',
56 mouseup: 'closeHandler'
57 }
58 },
59 onboardingIndex: 0,
60 states: ['state-0', 'state-1', 'state-2', 'state-3'],
61
62 /**
63 * Onboarding event handler. When clicking the close button,
64 * remove the onboarding and put the user back into the environment,
65 *
66 * @method closeHandler
67 * @param {Object} ev An event object (with a "currentTarget" attribute).
68 * @return {undefined} Mutates only.
69 */
70 closeHandler: function(ev) {
71 ev.halt();
72 var container = this.get('container');
73 container.hide();
74 Y.one('#environment-help').removeClass('hidden');
75 },
76
77 /**
78 * Show the container and hide the enviroment help.
79 *
80 * @method open
81 * @return {undefined} Mutates only.
82 */
83 open: function() {
84 this.onboardingIndex = 0;
85 this.drawContent();
86 this.onboarding.show();
87 Y.one('#environment-help').addClass('hidden');
88 },
89
90 /**
91 * Onboarding event handler. When clicking the next button,
92 * update the index counter, and update to the next step of onboarding.
93 *
94 * @method nextHandler
95 * @param {Object} ev An event object (with a "currentTarget" attribute).
96 * @return {undefined} Mutates only.
97 */
98 nextHandler: function(ev) {
99 ev.halt();
100 this.incrementIndex();
101 this.drawContent();
102 },
103
104 /**
105 * Onboarding event handler. When clicking the prev button,
106 * update the index counter, and update to the prev step of onboarding.
107 *
108 * @method prevHandler
109 * @param {Object} ev An event object (with a "currentTarget" attribute).
110 * @return {undefined} Mutates only.
111 */
112 prevHandler: function(ev) {
113 ev.halt();
114 this.decrementIndex();
115 this.drawContent();
116 },
117
118 /**
119 * Onboarding event handler. When hover and click the close cross.
120 *
121 * @method crossHandler
122 * @param {Object} ev An event object (with a "currentTarget" attribute).
123 * @return {undefined} Mutates only.
124 */
125 crossHandler: function(ev) {
126 var container = this.get('container');
127 var close_button = container.one('.onboarding-cross');
128 switch (ev._event.type) {
129 case 'mouseover':
130 close_button.replaceClass('close-inspector-normal',
131 'close-inspector-hover');
132 break;
133 case 'mouseout':
134 close_button.replaceClass('close-inspector-hover',
135 'close-inspector-normal');
136 break;
137 case 'mousedown':
138 close_button.replaceClass('close-inspector-hover',
139 'close-inspector-click');
140 break;
141 }
142 },
143
144 /**
145 * @method drawContent
146 * @return {undefined} Mutates only.
147 */
148 drawContent: function() {
149 var container = this.get('container');
150 var container_bg = container.one('#onboarding-background');
151
152 this.states.forEach(function(state, idx) {
153 container_bg.removeClass(state);
154 });
155 container_bg.addClass(this.states[this.onboardingIndex]);
156 },
157
158 /**
159 * @method incrementIndex
160 * @return {undefined} Mutates only.
161 */
162 incrementIndex: function() {
163 this.onboardingIndex = Math.min(
164 this.onboardingIndex + 1, this.states.length - 1);
165 },
166
167 /**
168 * @method decrementIndex
169 * @return {undefined} Mutates only.
170 */
171 decrementIndex: function() {
172 this.onboardingIndex = Math.max(this.onboardingIndex - 1, 0);
173
174 },
175
176 /**
177 * Render the page.
178 *
179 * Reveal the mask element, and show the onboarding window.
180 *
181 * @method render
182 * @return {undefined} Mutates only.
183 */
184 render: function() {
185 // In order to have the mask cover everything, it needs to be an
186 // immediate child of the body. In order for it to render immediately
187 // when the app loads, it needs to be in index.html.
188 this.onboarding = Y.one('body > #onboarding');
189 if (!this.onboarding) {
190 // No mask in the DOM, as is the case in tests.
191 return this;
192 }
193
194 this.get('container').setHTML(this.template());
195 this.open();
196
197 return this;
198 }
199
200 });
201
202
203}, '0.1.0', {
204 requires: [
205 'juju-templates',
206 'juju-view-utils',
207 'node',
208 'view'
209 ]
210});
0211
=== modified file 'lib/views/stylesheet.less'
--- lib/views/stylesheet.less 2013-10-17 00:17:47 +0000
+++ lib/views/stylesheet.less 2013-10-17 15:15:29 +0000
@@ -2003,6 +2003,178 @@
2003 font-size: 8pt;2003 font-size: 8pt;
2004 }2004 }
2005}2005}
2006#onboarding-background {
2007 display: block;
2008 position: absolute;
2009 top: 0;
2010 left: 0;
2011 width: 100%;
2012 height: 100%;
2013 z-index: 9999;
2014
2015 #onboarding-screen-mask {
2016 display: block;
2017 position: absolute;
2018 top: 80px;
2019 left: 0;
2020 width: 100%;
2021 height: 100%;
2022 z-index: 10000;
2023 }
2024
2025 #onboarding-message {
2026 .create-border-radius(@border-radius);
2027 display: block;
2028 z-index: 10001;
2029 position: relative;
2030 top: 100px;
2031 left: 350px;
2032 width: 320px;
2033 background-color: @inspector-background-color;
2034 padding: 20px;
2035
2036 .onboarding-cross {
2037 float: right;
2038 }
2039
2040 .header {
2041 margin-bottom: 20px;
2042 }
2043
2044 .header,
2045 .text {
2046 color: @charm-panel-configure-title-color;
2047 }
2048
2049 img {
2050 position: absolute;
2051 }
2052
2053 .panel {
2054 display: none;
2055 height: 169px;
2056 }
2057
2058 ul {
2059 position: relative;
2060 list-style: none;
2061 margin-left: 0;
2062 height: 57px;
2063
2064 li {
2065 display: inline;
2066 }
2067
2068 a {
2069 @box-shadow: inset 0 2px 2px rgba(0, 0, 0, 0.3);
2070 .create-box-shadow(@box-shadow);
2071 .create-border-radius(@bws-corner);
2072 background-color: @inspector-dark;
2073 display: inline-block;
2074 height: 40px;
2075 margin-top: 17px;
2076 padding: 0 30px;
2077 color: #fff;
2078 line-height: 40px;
2079
2080 &.onboarding-next,
2081 &.onboarding-start,
2082 &.onboarding-prev {
2083 float: right;
2084 }
2085 &.highlight {
2086 background-color: @charm-panel-orange;
2087 margin-left: 10px;
2088 }
2089 }
2090 }
2091 }
2092
2093 &.state-0 {
2094 #onboarding-message {
2095 .panel-0 {
2096 display: block;
2097 }
2098 ul a.onboarding-next,
2099 ul a.onboarding-prev {
2100 display: none;
2101 }
2102 }
2103
2104 }
2105
2106 &.state-1 {
2107 #onboarding-screen-mask {
2108 left: 290px;
2109 background-color: rgba(0, 0, 0, 0.75);
2110 }
2111 #onboarding-message {
2112 .panel-1 {
2113 display: block;
2114 }
2115 ul a.onboarding-next {
2116 display: inline-block;
2117 }
2118 ul a.onboarding-start {
2119 display: none;
2120 }
2121 }
2122 }
2123
2124 &.state-2 {
2125 #onboarding-screen-mask {
2126 left: 0;
2127 background-color: rgba(0, 0, 0, 0.75);
2128 }
2129 #onboarding-message {
2130 .panel-2 {
2131 display: block;
2132 }
2133 ul a.onboarding-next {
2134 display: inline-block;
2135 }
2136 ul a.onboarding-start {
2137 display: none;
2138 }
2139 .service-blocks {
2140 top: 210px;
2141 left: 125px;
2142 }
2143 }
2144 }
2145
2146 &.state-3 {
2147 #onboarding-screen-mask {
2148 left: 0;
2149 background-color: rgba(0, 0, 0, 0.75);
2150 }
2151 #onboarding-message {
2152 .panel-3 {
2153 display: block;
2154 }
2155 ul a.onboarding-close {
2156 background-color: @charm-panel-orange;
2157 margin-left: 10px;
2158 float: right;
2159 }
2160 ul a.onboarding-next {
2161 display: none;
2162 }
2163 ul a.onboarding-start {
2164 display: none;
2165 }
2166 .service-block {
2167 top: 320px;
2168 left: 90px;
2169 }
2170 .inspector {
2171 right: -370px;
2172 top: 0;
2173 }
2174 }
2175 }
2176
2177}
2006.alert {2178.alert {
2007 letter-spacing: normal;2179 letter-spacing: normal;
2008}2180}
20092181
=== modified file 'test/index.html'
--- test/index.html 2013-10-08 23:14:08 +0000
+++ test/index.html 2013-10-17 15:15:29 +0000
@@ -91,6 +91,7 @@
91 <script src="test_model.js"></script>91 <script src="test_model.js"></script>
92 <script src="test_model_bundle.js"></script>92 <script src="test_model_bundle.js"></script>
93 <script src="test_model_controller.js"></script>93 <script src="test_model_controller.js"></script>
94 <script src="test_onboarding.js"></script>
94 <script src="test_topology.js"></script>95 <script src="test_topology.js"></script>
95 <script src="test_topology_relation.js"></script>96 <script src="test_topology_relation.js"></script>
9697
9798
=== added file 'test/test_onboarding.js'
--- test/test_onboarding.js 1970-01-01 00:00:00 +0000
+++ test/test_onboarding.js 2013-10-17 15:15:29 +0000
@@ -0,0 +1,164 @@
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(function() {
23
24 describe('onboarding process', function() {
25 var container, env_help, OnboardingView, views, utils, Y;
26
27 before(function(done) {
28 Y = YUI(GlobalConfig).use(
29 'node-event-simulate',
30 'juju-tests-utils',
31 'juju-view-onboarding',
32 function(Y) {
33 utils = Y.namespace('juju-tests.utils');
34 views = Y.namespace('juju.views');
35 OnboardingView = views.OnboardingView;
36 done();
37 });
38 });
39
40 beforeEach(function() {
41 container = utils.makeContainer('onboarding');
42 env_help = utils.makeContainer('environment-help');
43 window.flags.onboard = true;
44 });
45
46 afterEach(function() {
47 container.remove(true);
48 env_help.remove(true);
49 window.flags = {};
50 });
51
52 after(function() {
53
54 });
55
56 it('should exist in the views namespace', function() {
57 assert(views.OnboardingView);
58 });
59
60 it('inits values correctly', function() {
61 var onboard = new OnboardingView();
62 assert.equal(onboard.onboardingIndex, 0);
63 });
64
65 it('increments screen index correctly', function() {
66 var onboard = new OnboardingView({
67 container: container
68 });
69
70 onboard.render();
71 onboard.nextHandler({halt: function() {}});
72 assert.equal(onboard.onboardingIndex, 1);
73 onboard.nextHandler({halt: function() {}});
74 assert.equal(onboard.onboardingIndex, 2);
75 });
76
77 it('decrements screen index correctly', function() {
78 var onboard = new OnboardingView({
79 container: container
80 });
81
82 onboard.render();
83 onboard.onboardingIndex = 2;
84 onboard.prevHandler({halt: function() {}});
85 assert.equal(onboard.onboardingIndex, 1);
86 onboard.prevHandler({halt: function() {}});
87 assert.equal(onboard.onboardingIndex, 0);
88 });
89
90 it('renders correctly on first load', function() {
91 var onboard = new OnboardingView({
92 container: container
93 });
94
95 onboard.render();
96 var background = container.one('#onboarding-background');
97 assert.isTrue(background instanceof Y.Node);
98 assert.isTrue(env_help.hasClass('hidden'));
99 assert.equal(container.getComputedStyle('display'), 'block');
100 assert.isTrue(background.hasClass('state-0'));
101 });
102
103 it('updates background css properly', function() {
104 var onboard = new OnboardingView({
105 container: container
106 });
107
108 onboard.render();
109 var background = container.one('#onboarding-background');
110 onboard.nextHandler({halt: function() {}});
111 assert.isTrue(background.hasClass('state-1'), 'should be state 1');
112 onboard.nextHandler({halt: function() {}});
113 assert.isTrue(background.hasClass('state-2'), 'should be 2');
114 onboard.prevHandler({halt: function() {}});
115 assert.isTrue(background.hasClass('state-1'), 'should be 1 again');
116 onboard.prevHandler({halt: function() {}});
117 assert.isTrue(background.hasClass('state-0'), 'should be 0 again');
118 onboard.prevHandler({halt: function() {}});
119 assert.isTrue(background.hasClass('state-0'), 'should stick to 0');
120 });
121
122 it('displays correct stage of onboarding', function() {
123 var onboard = new OnboardingView({
124 container: container
125 });
126
127 onboard.render();
128
129 var panel0 = container.one('.panel-0');
130 var panel1 = container.one('.panel-1');
131 var panel2 = container.one('.panel-2');
132 assert.equal(
133 panel0.getComputedStyle('display'), 'block');
134 onboard.nextHandler({halt: function() {}});
135 assert.equal(
136 panel1.getComputedStyle('display'), 'block');
137 onboard.nextHandler({halt: function() {}});
138 assert.equal(
139 panel2.getComputedStyle('display'), 'block');
140 onboard.prevHandler({halt: function() {}});
141 assert.equal(
142 panel1.getComputedStyle('display'), 'block');
143 onboard.prevHandler({halt: function() {}});
144 assert.equal(
145 panel0.getComputedStyle('display'), 'block');
146 onboard.prevHandler({halt: function() {}});
147 assert.equal(
148 panel0.getComputedStyle('display'), 'block');
149 });
150
151 it('closes onboarding', function() {
152 var onboard = new OnboardingView({
153 container: container
154 });
155
156 onboard.render();
157 var onboardingCross = container.one('.onboarding-cross');
158 assert.isTrue(onboardingCross instanceof Y.Node);
159 onboard.closeHandler({halt: function() {}});
160 assert.equal(container.getComputedStyle('display'), 'none');
161 assert.isFalse(env_help.hasClass('hidden'));
162 });
163 });
164})();

Subscribers

People subscribed via source and target branches