Merge lp:~hatch/juju-gui/unit-breakout-1253114 into lp:juju-gui/experimental

Proposed by Jeff Pihach
Status: Merged
Merged at revision: 1221
Proposed branch: lp:~hatch/juju-gui/unit-breakout-1253114
Merge into: lp:juju-gui/experimental
Diff against target: 150 lines (+55/-49)
2 files modified
app/views/databinding.js (+54/-49)
app/views/viewlets/unit-details.js (+1/-0)
To merge this branch: bzr merge lp:~hatch/juju-gui/unit-breakout-1253114
Reviewer Review Type Date Requested Status
Juju GUI Hackers Pending
Review via email: mp+197619@code.launchpad.net

Description of the change

Add support to mix in delayed delta changes

Due to a race condition the unit details view would sometimes not update
as per the databinding because there were some deltas which had not yet
been applied. This adds the functionality to mix these deltas in or
filter by them as was the previous functionality.

https://codereview.appspot.com/36850043/

To post a comment you must log in.
Revision history for this message
Jeff Pihach (hatch) wrote :
Download full text (4.8 KiB)

Reviewers: mp+197619_code.launchpad.net,

Message:
Please take a look.

Description:
Add support to mix in delayed delta changes

Due to a race condition the unit details view would sometimes not update
as per the databinding because there were some deltas which had not yet
been applied. This adds the functionality to mix these deltas in or
filter by them as was the previous functionality.

To QA:
In sandbox deploy service with 10 units, wait a minute or so for a
number
of deltas to come through. Then start clicking on units in the inspector
unit list to display the details, after viewing about 50 units if you
haven't
seen the unit details header unpopulated it's safe to assume that the
issue is resolved.

https://code.launchpad.net/~hatch/juju-gui/unit-breakout-1253114/+merge/197619

(do not edit description out of merge proposal)

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

Affected files (+24, -11 lines):
   A [revision details]
   M app/views/databinding.js
   M app/views/viewlets/unit-details.js

Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: <email address hidden>
+New revision: <email address hidden>

Index: app/views/databinding.js
=== modified file 'app/views/databinding.js'
--- app/views/databinding.js 2013-10-11 03:18:33 +0000
+++ app/views/databinding.js 2013-12-03 22:42:52 +0000
@@ -155,12 +155,15 @@

        @method deltaFromChange
        @param {Array} modelChangeKeys array of {String} keys that have
changed.
+ @param {Boolean} mixin if you want to mix the modelChangeKeys into
the
+ changed value list or filter to use only those bindings. Default
false.
        @return {Array} bindings array filtered by keys when present.
      */
- function deltaFromChange(modelChangeKeys) {
+ function deltaFromChange(modelChangeKeys, mixin) {
        /* jshint -W040 */
        // Ignore 'possible strict violation'
        var bindings = this._bindings;
+ mixin = mixin || false;
        var result = {bindings: [], wildcards: {}};
        // Handle wildcards.
        result.wildcards = indexBindings(bindings, function(binding) {
@@ -172,19 +175,26 @@

        if (modelChangeKeys !== undefined && modelChangeKeys.length !== 0) {
          // In this branch of the the conditional, we only have a specific
set
- // of keys that have changed, so we want to limit the resulting
+ // of keys that have changed, so we may want to limit the resulting
          // bindings appropriately.
- // Find the bindings that match the modelChangeKeys.
- var filteredBindings = bindings.filter(function(binding) {
- // Change events don't honor nested key paths. This means
- // we may update bindings that impact multiple DOM nodes
- // (our granularity is too low).
- return (modelChangeKeys.indexOf(binding.name.split('.')[0]) >
-1);
- });
+ var filteredBindings;
+ if (mixin) {
+ filteredBindings = bindings;
+ ...

Read more...

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

Hey Jeff. Thank you for tackling this tricky problem.

I think your attention on this area has indicated that resetDOMToModel
needs some changes to deltaFromChange, because it should also reset
dependents.

However, I don't think that your change to _modelDOMHandler is right.
It's too big. See my comments below. I could be wrong, but I'd like to
talk this through with you tomorrow.

Thanks,

Gary

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

https://codereview.appspot.com/36850043/diff/1/app/views/databinding.js#newcode159
app/views/databinding.js:159: changed value list or filter to use only
those bindings. Default false.
I want to remove this new parameter. See below.

https://codereview.appspot.com/36850043/diff/1/app/views/databinding.js#newcode176
app/views/databinding.js:176: if (modelChangeKeys !== undefined &&
modelChangeKeys.length !== 0) {
I suggest we change the rest of this code as follows.

var filteredBindings = bindings;
if (modelChangeKeys !== undefined && modelChangeKeys.length !== 0) {
   // In this branch of the the conditional, we only have a specific set
   // of keys that have changed, so we want to limit the resulting
   // bindings appropriately.
   var filteredBindings = bindings.filter(function(binding) {
     // Change events don't honor nested key paths. This means
     // we may update bindings that impact multiple DOM nodes
     // (our granularity is too low).
     return (modelChangeKeys.indexOf(binding.name.split('.')[0]) > -1);
   });
}

// Add dependents.
...

https://codereview.appspot.com/36850043/diff/1/app/views/databinding.js#newcode216
app/views/databinding.js:216: } else {
This branch would disappear. Now, if you don't specify modelChangeKeys,
you get bindings *plus* dependent bindings.

https://codereview.appspot.com/36850043/diff/1/app/views/databinding.js#newcode718
app/views/databinding.js:718: delta = deltaFromChange.call(this);
Shouldn't this include dependents? If so, the deltaFromChange function
could be a lot prettier. See discussion above.

https://codereview.appspot.com/36850043/diff/1/app/views/databinding.js#newcode872
app/views/databinding.js:872: delta = deltaFromChange.call(this,
this._unappliedChanges, true);
I'm proposing that this could be spelled

delta = deltaFromChange.call(this);

However, why do we want to ignore the fact that we know what the
unapplied changes are? It seems wrong. Could you explain? I have a
feeling that this is too blunt of a hammer.

If it *is* the right approach, we need a very good explanation in the
comments...*and* we should remove all references to _unappliedChanges,
because it is never used in your code.

https://codereview.appspot.com/36850043/

1220. By Jeff Pihach

cleanup refactor to simplify deltaFromChange and fix hidden bug in resetDOMToModel

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

*** Submitted:

Add support to mix in delayed delta changes

Due to a race condition the unit details view would sometimes not update
as per the databinding because there were some deltas which had not yet
been applied. This adds the functionality to mix these deltas in or
filter by them as was the previous functionality.

R=gary.poster
CC=
https://codereview.appspot.com/36850043

https://codereview.appspot.com/36850043/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'app/views/databinding.js'
2--- app/views/databinding.js 2013-10-11 03:18:33 +0000
3+++ app/views/databinding.js 2013-12-04 17:05:50 +0000
4@@ -170,45 +170,44 @@
5 return binding.name;
6 }, true);
7
8+ var filteredBindings = bindings;
9 if (modelChangeKeys !== undefined && modelChangeKeys.length !== 0) {
10 // In this branch of the the conditional, we only have a specific set
11- // of keys that have changed, so we want to limit the resulting
12+ // of keys that have changed, so we may want to limit the resulting
13 // bindings appropriately.
14+
15 // Find the bindings that match the modelChangeKeys.
16- var filteredBindings = bindings.filter(function(binding) {
17+ filteredBindings = bindings.filter(function(binding) {
18 // Change events don't honor nested key paths. This means
19 // we may update bindings that impact multiple DOM nodes
20 // (our granularity is too low).
21 return (modelChangeKeys.indexOf(binding.name.split('.')[0]) > -1);
22 });
23- // Add dependents.
24- // We make an index of all bindings to help with this.
25- var index = indexBindings(bindings, null, true);
26- var added = {};
27- filteredBindings.forEach(function(binding) {
28- if (binding.name === '*' ||
29- binding.name === '+') {
30- return;
31- }
32- result.bindings.push(binding);
33- if (binding.dependents) {
34- binding.dependents.forEach(function(dep) {
35- if (!added[dep]) {
36- added[dep] = true;
37- var depends = index[dep];
38- if (depends) {
39- result.bindings.push.apply(result.bindings, depends);
40- }
41+ }
42+
43+ // Add dependents.
44+ // We make an index of all bindings to help with this.
45+ var index = indexBindings(bindings, null, true);
46+ var added = {};
47+
48+ filteredBindings.forEach(function(binding) {
49+ if (binding.name === '*' ||
50+ binding.name === '+') {
51+ return;
52+ }
53+ result.bindings.push(binding);
54+ if (binding.dependents) {
55+ binding.dependents.forEach(function(dep) {
56+ if (!added[dep]) {
57+ added[dep] = true;
58+ var depends = index[dep];
59+ if (depends) {
60+ result.bindings.push.apply(result.bindings, depends);
61 }
62- });
63- }
64- });
65- } else {
66- // If we don't have modelChangeKeys, we simply want all of the
67- // existing bindings.
68- result.bindings.push.apply(result.bindings, bindings);
69- }
70-
71+ }
72+ });
73+ }
74+ });
75
76 return result;
77 }
78@@ -839,26 +838,33 @@
79 @param {Event} evt Y.Model change event.
80 */
81 BindingEngine.prototype._modelChangeHandler = function(evt) {
82- var keys, delta;
83+ var keys, delta, unappliedChanges = [];
84 var initialize = !evt; // If there is no event, this is an initialization.
85- if (Y.Lang.isArray(evt)) {
86- // Object.observe updates
87- keys = evt.map(function(update) { return update.name; });
88- } else {
89- keys = evt && Y.Object.keys(evt.changed);
90- }
91-
92- // Mix any unapplied changes into the key set
93- // updating this list. We then use that combined
94- // list to generate the binding set.
95- if (keys) {
96- keys.forEach(function(k) {
97- if (this._unappliedChanges.indexOf(k) === -1) {
98- this._unappliedChanges.push(k);
99- }
100- }, this);
101- }
102- delta = deltaFromChange.call(this, this._unappliedChanges);
103+
104+ // If this is an initialization then we want to force all
105+ // changes not just the unapplied changes.
106+ if (!initialize) {
107+ if (Y.Lang.isArray(evt)) {
108+ // Object.observe updates
109+ keys = evt.map(function(update) { return update.name; });
110+ } else {
111+ keys = evt && Y.Object.keys(evt.changed);
112+ }
113+
114+ // Mix any unapplied changes into the key set
115+ // updating this list. We then use that combined
116+ // list to generate the binding set.
117+ if (keys) {
118+ keys.forEach(function(k) {
119+ if (this._unappliedChanges.indexOf(k) === -1) {
120+ this._unappliedChanges.push(k);
121+ }
122+ }, this);
123+ }
124+ unappliedChanges = this._unappliedChanges;
125+ }
126+
127+ delta = deltaFromChange.call(this, unappliedChanges);
128
129 if (this._updateTimeout) {
130 this._updateTimeout.cancel();
131@@ -905,7 +911,6 @@
132 // identify conflicts and handle them.
133 //
134 // This is all done per-binding in the forEach loop below.
135-
136 var bindingEngine = this;
137
138 // updateDOM applies all the changes clearing the buffer.
139
140=== modified file 'app/views/viewlets/unit-details.js'
141--- app/views/viewlets/unit-details.js 2013-11-20 15:09:44 +0000
142+++ app/views/viewlets/unit-details.js 2013-12-04 17:05:50 +0000
143@@ -104,6 +104,7 @@
144 data += '<li>' + key + ': ' + value[key] + '</li>';
145 });
146 node.one('ul').setHTML(data);
147+ node.show();
148 } else {
149 node.hide();
150 }

Subscribers

People subscribed via source and target branches