Maintenance: Fix difference function to compare both ways and also make sure that the observer copies hashes to prevent references.

This commit is contained in:
Rolf Schmidt 2022-02-17 08:35:55 +01:00
parent 91dc61bbaa
commit 4cb5a7776b
9 changed files with 343 additions and 60 deletions

View file

@ -2,6 +2,7 @@ class App.ControllerObserver extends App.Controller
model: 'Ticket'
template: 'tba'
globalRerender: true
lastAttributes: undefined
###
observe:
@ -25,7 +26,7 @@ class App.ControllerObserver extends App.Controller
# rerender, e. g. on language change
if @globalRerender
@controllerBind('ui:rerender', =>
@lastAttributres = undefined
@lastAttributes = undefined
@maybeRender(App[@model].fullLocal(@object_id))
)
@ -43,32 +44,40 @@ class App.ControllerObserver extends App.Controller
if !@subscribeId
@subscribeId = object.subscribe(@subscribe)
# remember current attributes
return if !@hasChanged(object)
@render(object)
hasChanged: (object) =>
currentAttributes = {}
objectCloned = $.extend(true, {}, object)
if @observe
for key, active of @observe
if active
currentAttributes[key] = object[key]
if active && !_.isFunction(value)
currentAttributes[key] = objectCloned[key]
if @observeNot
for key, value of object
if key isnt 'cid' && !@observeNot[key] && !_.isFunction(value) && !_.isObject(value)
for key, value of objectCloned
if key isnt 'cid' && !@observeNot[key] && !_.isFunction(value)
currentAttributes[key] = value
if !@lastAttributres
@lastAttributres = {}
else
diff = difference(currentAttributes, @lastAttributres)
if !@lastAttributes
@lastAttributes = currentAttributes
return true
diff = difference(currentAttributes, @lastAttributes)
if _.isEmpty(diff)
@log 'debug', 'maybeRender no diff, no rerender'
return
return false
@log 'debug', 'maybeRender.diff', diff, @observe, @model
@lastAttributres = currentAttributes
@lastAttributes = currentAttributes
@render(object, diff)
true
render: (object, diff) =>
@log 'debug', 'render', @template, object, diff
render: (object) =>
@log 'debug', 'render', @template, object
@html App.view(@template)(
object: object
)

View file

@ -202,7 +202,7 @@ class Object extends App.ControllerObserver
value = $(e.target).html()
org = App.Organization.find(@object_id)
if org[name] isnt value
@lastAttributres[name] = value
@lastAttributes[name] = value
data = {}
data[name] = value
org.updateAttributes(data)

View file

@ -24,7 +24,7 @@ class Internal
internal = true
if article.internal == true
internal = false
ui.lastAttributres.internal = internal
ui.lastAttributes.internal = internal
article.updateAttributes(internal: internal)
# runtime update

View file

@ -221,7 +221,7 @@ class ArticleViewItem extends App.ControllerObserver
el: @$('.js-article-actions')
ticket: @ticket
article: article
lastAttributres: @lastAttributres
lastAttributes: @lastAttributes
form_id: @form_id
)

View file

@ -19,7 +19,7 @@ class App.TicketZoomTitle extends App.ControllerObserver
title = $(e.target).ceg() || ''
# update title
return if title is @lastAttributres.title
return if title is @lastAttributes.title
ticket = App.Ticket.find(@object_id)
ticket.title = title

View file

@ -220,7 +220,7 @@ class Object extends App.ControllerObserver
value = $(e.target).html()
user = App.User.find(@object_id)
if user[name] isnt value
@lastAttributres[name] = value
@lastAttributes[name] = value
data = {}
data[name] = value
user.updateAttributes(data)

View file

@ -65,9 +65,9 @@ Date.prototype.getWeek = function() {
function difference(object1, object2) {
var changes = {};
for (var name in object1) {
if (name in object2) {
if (_.isObject(object2[name]) && !_.isArray(object2[name])) {
_.uniq(Object.keys(object1).concat(Object.keys(object2))).forEach(function(name) {
if (name in object1 && name in object2) {
if (_.isObject(object1[name]) && !_.isArray(object1[name]) && _.isObject(object2[name]) && !_.isArray(object2[name])) {
var diff = difference(object1[name], object2[name]);
if (!_.isEmpty(diff)) {
changes[name] = diff;
@ -75,8 +75,10 @@ function difference(object1, object2) {
} else if (!_.isEqual(object1[name], object2[name])) {
changes[name] = object2[name];
}
} else {
changes[name] = object2[name]
}
}
})
return changes;
}

View file

@ -536,7 +536,9 @@ test('difference', function() {
object2 = {
key1: 123,
}
result = {}
result = {
key2: undefined
}
item = difference(object1, object2)
deepEqual(item, result)
@ -547,38 +549,106 @@ test('difference', function() {
key1: 123,
key2: 124
}
result = {
key2: 124
}
item = difference(object1, object2)
deepEqual(item, result)
object1 = {
customer_id: 1,
organization_id: 2,
}
object2 = {
customer_id: 1,
organization_id: null,
}
result = {
organization_id: null,
}
item = difference(object1, object2)
deepEqual(item, result)
object1 = {
customer_id: 1,
organization_id: null,
}
object2 = {
customer_id: 1,
organization_id: 2,
}
result = {
organization_id: 2,
}
item = difference(object1, object2)
deepEqual(item, result)
object1 = {
customer_id: 1,
preferences: { resolved: true },
}
object2 = {
customer_id: 1,
preferences: {},
}
result = {
preferences: { resolved: undefined }
}
item = difference(object1, object2)
deepEqual(item, result)
object1 = {
customer_id: 1,
}
object2 = {
customer_id: 1,
preferences: { resolved: true },
}
result = {
preferences: { resolved: true }
}
item = difference(object1, object2)
deepEqual(item, result)
object1 = {
customer_id: 1,
preferences: {},
}
object2 = {
customer_id: 1,
preferences: { resolved: true },
}
result = {
preferences: { resolved: true }
}
item = difference(object1, object2)
deepEqual(item, result)
object1 = {
customer_id: 1,
preferences: { resolved: false },
}
object2 = {
customer_id: 1,
preferences: { resolved: true },
}
result = {
preferences: { resolved: true }
}
item = difference(object1, object2)
deepEqual(item, result)
object1 = {
customer_id: 1,
preferences: { resolved: true },
}
object2 = {
customer_id: 1,
preferences: { resolved: true },
}
result = {}
item = difference(object1, object2)
deepEqual(item, result)
object1 = {
customer_id: 1,
organization_id: 2,
}
object2 = {
customer_id: 1,
organization_id: null,
}
result = {
organization_id: null,
}
item = difference(object1, object2)
deepEqual(item, result)
object1 = {
customer_id: 1,
organization_id: null,
}
object2 = {
customer_id: 1,
organization_id: 2,
}
result = {
organization_id: 2,
}
item = difference(object1, object2)
deepEqual(item, result)
});
test('auth - not existing user', function(assert) {

View file

@ -0,0 +1,202 @@
QUnit.test( "controller observer tests - observe", assert => {
App.Ticket.refresh([{
id: 1,
title: 'ticket',
state_id: 1,
customer_id: 33,
organization_id: 1,
owner_id: 1,
preferences: { a: 1, b: 2 },
}])
var observer1 = new App.ControllerObserver({
object_id: 1,
template: 'version',
observe: {
title: true,
preferences: true,
},
})
var ticket = App.Ticket.find(1)
assert.equal(false, observer1.hasChanged(ticket))
// track title changes
ticket.title = 'title 2'
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.title = undefined
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.title = 'title 3'
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
// track no owner_id changes
ticket.owner_id = 2
assert.equal(false, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
// track preferences changes
ticket.preferences['a'] = 3
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.preferences['c'] = 3
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
// track no new_attribute1 changes
ticket.new_attribute1 = 'na 3'
assert.equal(false, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.new_attribute2 = function() { console.log(1) }
assert.equal(false, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.new_attribute2 = function() { console.log(2) }
assert.equal(false, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
// track title changes
ticket.title = function() { console.log(1) }
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.title = function() { console.log(2) }
assert.equal(false, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.title = 1
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
});
QUnit.test( "controller observer tests - observeNot", assert => {
App.Ticket.refresh([{
id: 2,
title: 'ticket',
state_id: 1,
customer_id: 33,
organization_id: 1,
owner_id: 1,
preferences: { a: 1, b: 2 },
}])
var observer1 = new App.ControllerObserver({
object_id: 2,
template: 'version',
observeNot: {
title: true,
preferences: true,
},
})
var ticket = App.Ticket.find(2)
assert.equal(false, observer1.hasChanged(ticket))
// track no title changes
ticket.title = 'title 2'
assert.equal(false, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
// track owner_id changes
ticket.owner_id = 2
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.owner_id = undefined
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.owner_id = 3
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
// track no preferences changes
ticket.preferences['a'] = 3
assert.equal(false, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.preferences['c'] = 3
assert.equal(false, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
// track preferences2 changes
ticket.preferences2 = {}
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.preferences2['a'] = 3
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.preferences2['a'] = 2
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.preferences2['c'] = 3
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
// track new_attribute1 changes
ticket.new_attribute1 = 'na 3'
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
// track no new_attribute2 changes (because of function content)
ticket.new_attribute2 = function() { console.log(1) }
assert.equal(false, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.new_attribute2 = function() { console.log(2) }
assert.equal(false, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
// track owner_id changes (pnly if content has no function content)
ticket.owner_id = function() { console.log(1) }
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.owner_id = function() { console.log(2) }
assert.equal(false, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
ticket.owner_id = 1
assert.equal(true, observer1.hasChanged(ticket))
assert.equal(false, observer1.hasChanged(ticket))
});