Merge lp:~gary/juju-gui/fixsavetext into lp:juju-gui/experimental

Proposed by Gary Poster
Status: Needs review
Proposed branch: lp:~gary/juju-gui/fixsavetext
Merge into: lp:juju-gui/experimental
Diff against target: 234 lines (+109/-15)
5 files modified
app/templates/service-configuration.partial (+1/-1)
app/templates/service-constraints-viewlet.handlebars (+2/-2)
app/views/databinding.js (+3/-3)
app/views/inspector.js (+31/-5)
lib/views/juju-inspector.less (+72/-4)
To merge this branch: bzr merge lp:~gary/juju-gui/fixsavetext
Reviewer Review Type Date Requested Status
Juju GUI Hackers Pending
Review via email: mp+183996@code.launchpad.net

Description of the change

Fix constraints save and add save confirmation

To QA, deploy a service with the inspector, and then reopen deployed inspector. In configuration and constraints, make changes and click save. The save button should now not change text when you click on it in the constraints tab. The save (and cancel) buttons only appear when there are changes to be saved. The fields correctly recognize when changes are reverted. When changes are saved, the field flashes green to show success.

checkboxes do not work properly in this branch: Rick is working on that. The cancel button does not work: that will be a separate branch.

For comment and discussion, code and UX. The green flash for fields on save is not as described by UX, but the desired display will be a lot more time consuming--and fragile, I am afraid--than what I have here. I am hoping this is a reasonable compromise.

I hope discussion will answer UX issues, as well as resolve what is appropriate for testing. I am a bit too focused on getting this out the door, so need some outside perspective.

https://codereview.appspot.com/13505044/

To post a comment you must log in.
Revision history for this message
Gary Poster (gary) wrote :

A code review. Reviewers: mp+183996_code.launchpad.net,

Message:
Please take a look.

Description:
Fix constraints save and add save confirmation

To QA, deploy a service with the inspector, and then reopen deployed
inspector. In configuration and constraints, make changes and click
save. The save button should now not change text when you click on it
in the constraints tab. The save (and cancel) buttons only appear when
there are changes to be saved. The fields correctly recognize when
changes are reverted. When changes are saved, the field flashes green
to show success.

checkboxes do not work properly in this branch: Rick is working on that.
  The cancel button does not work: that will be a separate branch.

For comment and discussion, code and UX. The green flash for fields on
save is not as described by UX, but the desired display will be a lot
more time consuming--and fragile, I am afraid--than what I have here. I
am hoping this is a reasonable compromise.

I hope discussion will answer UX issues, as well as resolve what is
appropriate for testing. I am a bit too focused on getting this out the
door, so need some outside perspective.

https://code.launchpad.net/~gary/juju-gui/fixsavetext/+merge/183996

(do not edit description out of merge proposal)

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

Affected files +111, -15:
   A [revision details]
   M app/templates/service-configuration.partial
   M app/templates/service-constraints-viewlet.handlebars
   M app/views/databinding.js
   M app/views/inspector.js
   M lib/views/juju-inspector.less

Revision history for this message
Jeff Pihach (hatch) wrote :

Looking good but there is some duplication of work, plz see below.

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

https://codereview.appspot.com/13505044/diff/1/app/views/inspector.js#newcode1047
app/views/inspector.js:1047: if (!this.modifiedKeys) {
When a user changes the value of an input the databinding engine keeps
track of these changes via it's _storeChanged method on line 609 of
databinding.js. This method keeps track of these changes in each
viewlets _changedvalues method. It would be nice if you could use this
data set instead of trying to keep track of it yourself. If you need
reference to these values in this changed method you may need to pass it
into the method call on line 622.

https://codereview.appspot.com/13505044/

Unmerged revisions

1005. By Gary Poster

lint

1004. By Gary Poster

fix constraint save text; add confirmation of changes for constraints and config

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'app/templates/service-configuration.partial'
2--- app/templates/service-configuration.partial 2013-09-04 10:44:34 +0000
3+++ app/templates/service-configuration.partial 2013-09-05 00:44:43 +0000
4@@ -48,7 +48,7 @@
5 </div>
6 {{/settings}}
7 {{#unless ghost}}
8-<div class="yui3-g controls configuration-buttons">
9+<div class="yui3-g controls closed configuration-buttons">
10 <div class="yui3-u-1-2">
11 <button class="cancel">Cancel</button>
12 </div>
13
14=== modified file 'app/templates/service-constraints-viewlet.handlebars'
15--- app/templates/service-constraints-viewlet.handlebars 2013-08-06 20:49:47 +0000
16+++ app/templates/service-constraints-viewlet.handlebars 2013-09-05 00:44:43 +0000
17@@ -1,7 +1,7 @@
18 <div class="view-container">
19- <legend>{{service.displayName}} constraints</legend>
20+ <legend>Constraints for New Units</legend>
21 {{> service-constraints-viewlet}}
22- <div class="controls">
23+ <div class="controls closed">
24 <button type="button" class="save-constraints confirm">Confirm</button>
25 </div>
26 </div>
27
28=== modified file 'app/views/databinding.js'
29--- app/views/databinding.js 2013-09-04 15:26:55 +0000
30+++ app/views/databinding.js 2013-09-05 00:44:43 +0000
31@@ -49,11 +49,11 @@
32 },
33 input: {
34 'get': function(node) { return node.get('value');},
35- 'set': function(node, value) { node.set('value', value);}
36+ 'set': function(node, value) { node.set('value', value || '');}
37 },
38 textarea: {
39 'get': function(node) { return node.get('value');},
40- 'set': function(node, value) { node.set('value', value);}
41+ 'set': function(node, value) { node.set('value', value || '');}
42 },
43 'default': {
44 'get': function(node) { return node.get('text');},
45@@ -607,7 +607,7 @@
46 @param {Object} viewlet reference.
47 */
48 BindingEngine.prototype._storeChanged = function(e, viewlet) {
49- var key = e.currentTarget.getData('bind'),
50+ var key = e.target.getData('bind'),
51 save = true;
52
53 viewlet._changedValues.forEach(function(value) {
54
55=== modified file 'app/views/inspector.js'
56--- app/views/inspector.js 2013-09-04 15:08:24 +0000
57+++ app/views/inspector.js 2013-09-05 00:44:43 +0000
58@@ -1065,12 +1065,22 @@
59
60 var ConflictMixin = {
61 'changed': function(node, key, field) {
62- var modelValue = this.model.get(key);
63+ if (!this.modifiedKeys) {
64+ this.modifiedKeys = {};
65+ }
66+ var modelValue = this.model.get(key) || '';
67 var fieldValue = field.get(node);
68+ var controls = this.container.one('.controls');
69 if (modelValue !== fieldValue) {
70- node.addClass('modified');
71+ node.replaceClass('change-saved', 'modified');
72+ this.modifiedKeys[key] = true;
73+ controls.removeClass('closed');
74 } else {
75 node.removeClass('modified');
76+ delete this.modifiedKeys[key];
77+ if (Object.keys(this.modifiedKeys).length === 0) {
78+ controls.addClass('closed');
79+ }
80 }
81 },
82 'conflict': function(node, model, viewletName, resolve, binding) {
83@@ -1131,11 +1141,27 @@
84 '.conflict', this));
85 },
86 'unsyncedFields': function(dirtyFields) {
87- this.container.one('.controls .confirm').setHTML('Overwrite');
88+ var node = this.container.one('.controls .confirm');
89+ if (!node.getData('originalText')) {
90+ node.setData('originalText', node.getHTML());
91+ }
92+ node.setHTML('Overwrite');
93 },
94 'syncedFields': function() {
95- this.container.one('.controls .confirm').setHTML('Save Changes');
96- this.container.all('.modified').removeClass('modified');
97+ var controls = this.container.one('.controls');
98+ var node = controls.one('.confirm');
99+ var title = node.getData('originalText');
100+ var modified = this.container.all('.modified');
101+ if (title) {
102+ node.setHTML(title);
103+ }
104+ modified.replaceClass('modified', 'change-saved');
105+ // animationend handlers don't work reliably, once you hook them up
106+ // with the associated custom browser names (e.g. webkitAnimationEnd)
107+ // on the raw DOM node, so don't even bother with them.
108+ Y.later(1000, modified, function() {
109+ this.removeClass('change-saved');});
110+ controls.addClass('closed');
111 }
112 };
113
114
115=== modified file 'lib/views/juju-inspector.less'
116--- lib/views/juju-inspector.less 2013-09-04 10:53:54 +0000
117+++ lib/views/juju-inspector.less 2013-09-05 00:44:43 +0000
118@@ -1,4 +1,5 @@
119 @inspector-background-color: #221e1c;
120+@inspector-changed-field: #dedede;
121 @inspector-controls-height: 67px;
122 @inspector-divider-bottom: rgba(0, 0, 0, 0.3);
123 @inspector-divider-top: rgba(255, 255, 255, 0.05);
124@@ -11,6 +12,54 @@
125 @disabled-input-background-color: #727272;
126 @disabled-input-text-color: #252525;
127
128+@-webkit-keyframes pulse-green {
129+ 0% {
130+ background-color: @inspector-changed-field;
131+ }
132+ 10% {
133+ background-color: #38b44a;
134+ }
135+ 100% {
136+ background-color: white;
137+ }
138+}
139+
140+@-moz-keyframes pulse-green {
141+ 0% {
142+ background-color: @inspector-changed-field;
143+ }
144+ 10% {
145+ background-color: #38b44a;
146+ }
147+ 100% {
148+ background-color: white;
149+ }
150+}
151+
152+@-o-keyframes pulse-green {
153+ 0% {
154+ background-color: @inspector-changed-field;
155+ }
156+ 10% {
157+ background-color: #38b44a;
158+ }
159+ 100% {
160+ background-color: white;
161+ }
162+}
163+
164+@keyframes pulse-green {
165+ 0% {
166+ background-color: @inspector-changed-field;
167+ }
168+ 10% {
169+ background-color: #38b44a;
170+ }
171+ 100% {
172+ background-color: white;
173+ }
174+}
175+
176 .yui3-juju-inspector {
177 input[type=text]::-ms-clear { display: none; }
178
179@@ -208,6 +257,15 @@
180 margin-top: 20px;
181 border-top: 1px solid @inspector-divider-top;
182 border-bottom: 1px solid @inspector-divider-bottom;
183+ overflow: hidden;
184+ height: 70px;
185+ -moz-transition: .3s, height .3s;
186+ -webkit-transition: .25s, height .3s;
187+ transition: .3s, height .3s;
188+
189+ &.closed {
190+ height: 0;
191+ }
192
193 button {
194 .create-border-radius(@border-radius);
195@@ -661,7 +719,7 @@
196 .resolver {
197 color: black;
198 background-color: white;
199- border: 1px solid #dedede;
200+ border: 1px solid @inspector-changed-field;
201 border-radius: 1px;
202
203 div {
204@@ -669,17 +727,27 @@
205 }
206 }
207 .modified {
208- background-color: #dedede;
209+ background-color: @inspector-changed-field;
210 background-image: url(/juju-ui/assets/images/field-changed.png);
211 }
212 .conflict-pending {
213- background-color: #dedede;
214+ background-color: @inspector-changed-field;
215 background-image: url(/juju-ui/assets/images/field-conflict.png);
216 }
217 .conflict {
218- background-color: #dedede;
219+ background-color: @inspector-changed-field;
220 background-image: url(/juju-ui/assets/images/field-resolved.png);
221 }
222+ .change-saved {
223+ -webkit-animation: pulse-green 1s;
224+ -moz-animation: pulse-green 1s;
225+ -o-animation: pulse-green 1s;
226+ animation: pulse-green 1s;
227+ -webkit-animation-fill-mode: forwards;
228+ -moz-animation-fill-mode: forwards;
229+ -o-animation-fill-mode: forwards;
230+ animation-fill-mode: forwards;
231+ }
232 }
233 .toggle {
234 padding: 10px @inspector-main-padding;

Subscribers

People subscribed via source and target branches