From c707135ccde115b7a4a4fe8b522fdacc723cfb32 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Sat, 13 Oct 2012 20:47:21 +0200 Subject: [PATCH] First spike of 'isComplete' functionality When we get payload from pusher, we usually don't send the entire record. Initially such records where fetched from server right away to get missing data. This was done becuase Ember can't tell if given data is complete or not and just assumes that the record is loaded. To not fire unneeded request, this code sets incomplete flag on records loaded from pusher and loads the rest of the data only if needed. --- assets/scripts/app/store.coffee | 42 +++++++++++++++++---- assets/scripts/app/templates/jobs/show.hbs | 2 +- assets/scripts/app/templates/repos/show.hbs | 2 +- assets/scripts/app/views/build.coffee | 4 +- assets/scripts/app/views/repo/show.coffee | 4 +- assets/scripts/lib/travis/model.coffee | 20 +++++++++- public/scripts/app.js | 2 +- public/scripts/min/app.js | 2 +- public/version | 2 +- 9 files changed, 61 insertions(+), 19 deletions(-) diff --git a/assets/scripts/app/store.coffee b/assets/scripts/app/store.coffee index c7192367..4b9a2b6f 100644 --- a/assets/scripts/app/store.coffee +++ b/assets/scripts/app/store.coffee @@ -8,6 +8,22 @@ Travis.Store = DS.Store.extend revision: 4 adapter: Travis.RestAdapter.create() + load: (type, id, hash) -> + result = @_super.apply this, arguments + + if result && result.clientId + # I assume that everything that goes through load is complete record + # representation, incomplete hashes from pusher go through merge() + record = @findByClientId type, result.clientId + record.set 'incomplete', false + record.set 'complete', true + # setting both incomplete and complete may be weird, but it's easier to + # work with both values. I need to check if record has already been completed + # and in order to do that, without having 'complete', I would need to check + # for incomplete == false, which looks worse + + result + merge: (type, id, hash) -> if hash == undefined hash = id @@ -29,11 +45,7 @@ Travis.Store = DS.Store.extend if record = recordCache[clientId] record.send('didChangeData') else - # that's nasty, but will do for now - # if event is triggered for a record - # that's not yet available, just use find - # to make a request to fetch it - clientId = @find(type, id).get('clientId') + clientId = @pushHash(hash, id, type) if clientId DATA_PROXY.savedData = hash @@ -59,9 +71,23 @@ Travis.Store = DS.Store.extend _loadOne: (store, type, json) -> root = type.singularName() - @adapter.sideload(store, type, json, root) - @merge(type, json[root]) - @_updateAssociations(type, root, json[root]) + # we get other types of records only on build, it comes with repository + # attached. I don't want to use store.sideload here as it will not use merge, + # if we need sideload becasue we have side records with other events it needs to + # be revised + if type == Travis.Build && json.repository + result = @_loadIncomplete(Travis.Repo, 'repository', json.repository) + @_loadIncomplete(type, root, json[root]) + + _loadIncomplete: (type, root, hash) -> + result = @merge(type, hash) + + if result && result.clientId + record = @findByClientId(type, result.clientId) + unless record.get('complete') + record.set 'incomplete', true + + @_updateAssociations(type, root, hash) _loadMany: (store, type, json) -> root = type.pluralName() diff --git a/assets/scripts/app/templates/jobs/show.hbs b/assets/scripts/app/templates/jobs/show.hbs index 5dd669e6..57ef426d 100644 --- a/assets/scripts/app/templates/jobs/show.hbs +++ b/assets/scripts/app/templates/jobs/show.hbs @@ -1,5 +1,5 @@ {{#with view}} - {{#if job.isLoaded}} + {{#if job.isComplete}}
diff --git a/assets/scripts/app/templates/repos/show.hbs b/assets/scripts/app/templates/repos/show.hbs index b01e0dec..8eec166e 100644 --- a/assets/scripts/app/templates/repos/show.hbs +++ b/assets/scripts/app/templates/repos/show.hbs @@ -2,7 +2,7 @@ {{#if view.isEmpty}} {{view Travis.ReposEmptyView}} {{else}} - {{#if view.repo.isLoaded}} + {{#if view.repo.isComplete}} {{#with view.repo}}

{{slug}} diff --git a/assets/scripts/app/views/build.coffee b/assets/scripts/app/views/build.coffee index 688bd4de..a1ea3014 100644 --- a/assets/scripts/app/views/build.coffee +++ b/assets/scripts/app/views/build.coffee @@ -55,8 +55,8 @@ currentItemBinding: 'build' loading: (-> - !@get('build.isLoaded') - ).property('build.isLoaded') + !@get('build.isComplete') + ).property('build.isComplete') color: (-> Travis.Helpers.colorForResult(@get('build.result')) diff --git a/assets/scripts/app/views/repo/show.coffee b/assets/scripts/app/views/repo/show.coffee index a84ad758..5511a1b0 100644 --- a/assets/scripts/app/views/repo/show.coffee +++ b/assets/scripts/app/views/repo/show.coffee @@ -6,8 +6,8 @@ repoBinding: 'controller.repo' class: (-> - 'loading' if !@get('repo.isLoaded') && !@get('isEmpty') - ).property('repo.isLoaded') + 'loading' if !@get('repo.isComplete') && !@get('isEmpty') + ).property('repo.isComplete') isEmpty: (-> @get('repos.length') == 0 diff --git a/assets/scripts/lib/travis/model.coffee b/assets/scripts/lib/travis/model.coffee index fba6e01e..0e3202f6 100644 --- a/assets/scripts/lib/travis/model.coffee +++ b/assets/scripts/lib/travis/model.coffee @@ -3,14 +3,30 @@ id: DS.attr('number') refresh: -> - id = @get('id') - Travis.app.store.adapter.find(Travis.app.store, @constructor, id) if id + if id = @get('id') + store = @get('store') + store.adapter.find store, @constructor, id update: (attrs) -> $.each attrs, (key, value) => @set(key, value) unless key is 'id' this + isComplete: (-> + if @get 'incomplete' + @loadTheRest() + false + else + @set 'isCompleting', false + @get 'isLoaded' + ).property('incomplete', 'isLoaded') + + loadTheRest: -> + return if @get('isCompleting') + @set 'isCompleting', true + + @refresh() + @Travis.Model.reopenClass find: -> if arguments.length == 0 diff --git a/public/scripts/app.js b/public/scripts/app.js index 5a7e7363..f9ff1162 100644 --- a/public/scripts/app.js +++ b/public/scripts/app.js @@ -29619,4 +29619,4 @@ var _require=function(){function c(a,c){document.addEventListener?a.addEventList ++g&&setTimeout(c,0)})}}(); (function(){!window.WebSocket&&window.MozWebSocket&&(window.WebSocket=window.MozWebSocket);if(window.WebSocket)Pusher.Transport=window.WebSocket,Pusher.TransportType="native";var c=(document.location.protocol=="http:"?Pusher.cdn_http:Pusher.cdn_https)+Pusher.VERSION,a=[];window.JSON||a.push(c+"/json2"+Pusher.dependency_suffix+".js");if(!window.WebSocket)window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION=!0,a.push(c+"/flashfallback"+Pusher.dependency_suffix+".js");var b=function(){return window.WebSocket?function(){Pusher.ready()}: function(){window.WebSocket?(Pusher.Transport=window.WebSocket,Pusher.TransportType="flash",window.WEB_SOCKET_SWF_LOCATION=c+"/WebSocketMain.swf",WebSocket.__addTask(function(){Pusher.ready()}),WebSocket.__initialize()):(Pusher.Transport=null,Pusher.TransportType="none",Pusher.ready())}}(),e=function(a){var b=function(){document.body?a():setTimeout(b,0)};b()},g=function(){e(b)};a.length>0?_require(a,g):g()})(); -;minispade.register('app', "(function() {(function() {\nminispade.require('auth');\nminispade.require('controllers');\nminispade.require('helpers');\nminispade.require('models');\nminispade.require('pusher');\nminispade.require('routes');\nminispade.require('slider');\nminispade.require('store');\nminispade.require('tailing');\nminispade.require('templates');\nminispade.require('views');\nminispade.require('config/locales');\nminispade.require('data/sponsors');\n\n Travis.reopen({\n App: Em.Application.extend({\n autoinit: false,\n currentUserBinding: 'auth.user',\n authStateBinding: 'auth.state',\n init: function() {\n this._super.apply(this, arguments);\n this.store = Travis.Store.create();\n this.store.loadMany(Travis.Sponsor, Travis.SPONSORS);\n this.set('auth', Travis.Auth.create({\n app: this,\n endpoint: Travis.config.api_endpoint\n }));\n this.slider = new Travis.Slider();\n this.pusher = new Travis.Pusher(Travis.config.pusher_key);\n return this.tailing = new Travis.Tailing();\n },\n signIn: function() {\n return this.get('auth').signIn();\n },\n autoSignIn: function() {\n return this.get('auth').autoSignIn();\n },\n signOut: function() {\n this.get('auth').signOut();\n return this.get('router').send('afterSignOut');\n },\n receive: function() {\n return this.store.receive.apply(this.store, arguments);\n },\n toggleSidebar: function() {\n var element;\n $('body').toggleClass('maximized');\n element = $('');\n $('#top .profile').append(element);\n Em.run.later((function() {\n return element.remove();\n }), 10);\n element = $('');\n $('#repo').append(element);\n return Em.run.later((function() {\n return element.remove();\n }), 10);\n }\n })\n });\n\n}).call(this);\n\n})();\n//@ sourceURL=app");minispade.register('auth', "(function() {(function() {\n\n this.Travis.Auth = Ember.Object.extend({\n iframe: $('