Merge pull request #414 from travis-ci/web-on-v3

Moving travis-web to V3 API
This commit is contained in:
Piotr Sarnacki 2015-12-09 14:39:11 +01:00
commit 6ad07924d3
118 changed files with 1368 additions and 852 deletions

View File

@ -3,7 +3,8 @@
"document", "document",
"window", "window",
"-Promise", "-Promise",
"jQuery" "jQuery",
"Visibility"
], ],
"browser": true, "browser": true,
"boss": true, "boss": true,

View File

@ -16,8 +16,8 @@ matrix:
fast_finish: true fast_finish: true
#addons: addons:
# sauce_connect: true sauce_connect: true
sudo: false sudo: false

3
.watchmanconfig Normal file
View File

@ -0,0 +1,3 @@
{
"ignore_dirs": ["tmp", "dist"]
}

View File

@ -2,6 +2,8 @@
`import config from 'travis/config/environment'` `import config from 'travis/config/environment'`
Adapter = DS.ActiveModelAdapter.extend Adapter = DS.ActiveModelAdapter.extend
auth: Ember.inject.service()
host: config.apiEndpoint host: config.apiEndpoint
coalesceFindRequests: true coalesceFindRequests: true
@ -12,13 +14,13 @@ Adapter = DS.ActiveModelAdapter.extend
hash.headers['accept'] = 'application/json; version=2' hash.headers['accept'] = 'application/json; version=2'
if token = Travis.sessionStorage.getItem('travis.token') if token = @get('auth').token()
hash.headers['Authorization'] ||= "token #{token}" hash.headers['Authorization'] ||= "token #{token}"
hash hash
findMany: (store, type, ids) -> findMany: (store, type, ids) ->
@ajax(@buildURL(type.typeKey), 'GET', data: { ids: ids }) @ajax(@buildURL(type.modelName), 'GET', data: { ids: ids })
handleResponse: (status, headers, payload) -> handleResponse: (status, headers, payload) ->
if status > 299 if status > 299

9
app/adapters/hook.js Normal file
View File

@ -0,0 +1,9 @@
import ApplicationAdapter from 'travis/adapters/application';
export default ApplicationAdapter.extend({
updateRecord(store, type, snapshot) {
return this._super(...arguments).then( (data) => {
return { hook: { id: snapshot.id } };
});
}
});

26
app/adapters/repo.js Normal file
View File

@ -0,0 +1,26 @@
import V3Adapter from 'travis/adapters/v3';
export default V3Adapter.extend({
defaultSerializer: '-repo',
buildUrl(modelName, id, snapshot, requestType, query) {
var url = this._super(...arguments);
return url;
},
ajaxOptions(url, type, options) {
var hash = options || {};
if(!hash.data) {
hash.data = {};
}
if(hash.data.include) {
hash.data.include += ',repository.default_branch,branch.last_build,build.commit';
} else {
hash.data.include = 'repository.default_branch,branch.last_build,build.commit';
}
return this._super(url, type, hash);
}
});

View File

@ -19,6 +19,7 @@ Adapter = ApplicationAdapter.extend
id = Ember.get(record, 'id') id = Ember.get(record, 'id')
this.ajax(this.urlPrefix() + '/ssh_key/' + id, "PATCH", { data: data }) this.ajax(this.urlPrefix() + '/ssh_key/' + id, "PATCH", { data: data }).then (data) ->
data.ssh_key
`export default Adapter` `export default Adapter`

58
app/adapters/v3.js Normal file
View File

@ -0,0 +1,58 @@
import Ember from 'ember';
import DS from 'ember-data';
import config from 'travis/config/environment';
export default DS.RESTAdapter.extend({
auth: Ember.inject.service(),
host: config.apiEndpoint,
sortQueryParams: false,
coalesceFindRequests: false,
headers: {
'Travis-API-Version': '3',
'Accept': 'application/json',
'Content-Type': 'application/json'
},
ajaxOptions: function(url, type, options) {
var hash = this._super(...arguments);
hash.headers = hash.headers || {};
var token;
if(token = this.get('auth').token()) {
hash.headers['Authorization'] = "token " + token;
}
return hash;
},
// TODO: I shouldn't override this method as it's private, a better way would
// be to create my own URL generator
_buildURL: function(modelName, id) {
var url = [];
var host = Ember.get(this, 'host');
var prefix = this.urlPrefix();
var path;
if (modelName) {
path = this.pathForType(modelName, id);
if (path) { url.push(path); }
}
if (id) { url.push(encodeURIComponent(id)); }
if (prefix) { url.unshift(prefix); }
url = url.join('/');
if (!host && url && url.charAt(0) !== '/') {
url = '/' + url;
}
return url;
},
pathForType: function(modelName, id) {
var underscored = Ember.String.underscore(modelName);
return id ? underscored : Ember.String.pluralize(underscored);
}
});

View File

@ -1,7 +1,7 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import Ajax from 'travis/utils/ajax'`
CachesItemComponent = Ember.Component.extend CachesItemComponent = Ember.Component.extend
ajax: Ember.inject.service()
tagName: 'li' tagName: 'li'
classNames: ['cache-item'] classNames: ['cache-item']
@ -20,7 +20,7 @@ CachesItemComponent = Ember.Component.extend
deletingDone = => @set('isDeleting', false) deletingDone = => @set('isDeleting', false)
repo = @get('repo') repo = @get('repo')
Ajax.ajax("/repos/#{repo.get('id')}/caches", "DELETE", data: data).then(deletingDone, deletingDone).then => @get('ajax').ajax("/repos/#{repo.get('id')}/caches", "DELETE", data: data).then(deletingDone, deletingDone).then =>
@get('caches').removeObject(@get('cache')) @get('caches').removeObject(@get('cache'))

View File

@ -1,10 +1,8 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import Ajax from 'travis/utils/ajax'`
`import config from 'travis/config/environment'` `import config from 'travis/config/environment'`
NoBuildsComponent = Ember.Component.extend NoBuildsComponent = Ember.Component.extend
actions:
actions:
triggerBuild: () -> triggerBuild: () ->
@set('isLoading', true) @set('isLoading', true)
apiEndpoint = config.apiEndpoint apiEndpoint = config.apiEndpoint

View File

@ -15,6 +15,10 @@ ReposListItemComponent = Ember.Component.extend Polling,
@get('repo') == @get('selectedRepo') @get('repo') == @get('selectedRepo')
).property('selectedRepo') ).property('selectedRepo')
color: (->
colorForState(@get('repo.defaultBranch.lastBuild.state'))
).property('repo.defaultBranch.lastBuild.state')
scrollTop: (-> scrollTop: (->
if (window.scrollY > 0) if (window.scrollY > 0)
$('html, body').animate({scrollTop: 0}, 200) $('html, body').animate({scrollTop: 0}, 200)

View File

@ -1,6 +0,0 @@
`import Ember from 'ember'`
ReposListComponent = Ember.Component.extend
tagName: 'ul'
`export default ReposListComponent`

View File

@ -0,0 +1,7 @@
import Ember from 'ember';
var ReposListComponent = Ember.Component.extend({
tagName: 'ul'
});
export default ReposListComponent;

View File

@ -1,5 +1,4 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import Ajax from 'travis/utils/ajax'`
`import config from 'travis/config/environment'` `import config from 'travis/config/environment'`
TravisStatusComponent = Ember.Component.extend TravisStatusComponent = Ember.Component.extend

View File

@ -2,8 +2,7 @@
Controller = Ember.Controller.extend Controller = Ember.Controller.extend
allHooks: [] allHooks: []
needs: ['currentUser'] userBinding: 'auth.currentUser'
userBinding: 'controllers.currentUser.model'
init: -> init: ->
@_super.apply this, arguments @_super.apply this, arguments
@ -22,7 +21,7 @@ Controller = Ember.Controller.extend
reloadHooks: -> reloadHooks: ->
if login = @get('model.login') if login = @get('model.login')
hooks = @store.find('hook', all: true, owner_name: login) hooks = @store.query('hook', all: true, owner_name: login)
hooks.then () -> hooks.then () ->
hooks.set('isLoaded', true) hooks.set('isLoaded', true)

View File

@ -1,7 +1,7 @@
`import Ember from 'ember'` `import Ember from 'ember'`
Controller = Ember.Controller.extend Controller = Ember.Controller.extend
needs: ['currentUser', 'repos'] repos: Ember.inject.controller()
userBinding: 'controllers.currentUser' userBinding: 'auth.currentUser'
`export default Controller` `export default Controller`

View File

@ -3,11 +3,11 @@
`import GithubUrlPropertievs from 'travis/mixins/github-url-properties'` `import GithubUrlPropertievs from 'travis/mixins/github-url-properties'`
Controller = Ember.Controller.extend GithubUrlPropertievs, Controller = Ember.Controller.extend GithubUrlPropertievs,
needs: ['repo', 'currentUser'] repoController: Ember.inject.controller('repo')
repoBinding: 'controllers.repo.repo' repoBinding: 'repoController.repo'
commitBinding: 'build.commit' commitBinding: 'build.commit'
currentUserBinding: 'controllers.currentUser.model' currentUserBinding: 'auth.currentUser'
tabBinding: 'controllers.repo.tab' tabBinding: 'repoController.tab'
sendFaviconStateChanges: true sendFaviconStateChanges: true
currentItemBinding: 'build' currentItemBinding: 'build'

View File

@ -4,10 +4,10 @@ Controller = Ember.ArrayController.extend
sortAscending: false sortAscending: false
sortProperties: ['number'] sortProperties: ['number']
needs: ['repo'] repoController: Ember.inject.controller('repo')
repoBinding: 'controllers.repo.repo' repoBinding: 'repoController.repo'
tabBinding: 'controllers.repo.tab' tabBinding: 'repoController.tab'
isLoadedBinding: 'content.isLoaded' isLoadedBinding: 'content.isLoaded'
isLoadingBinding: 'content.isLoading' isLoadingBinding: 'content.isLoading'
@ -53,7 +53,7 @@ Controller = Ember.ArrayController.extend
if type? if type?
options.event_type = type.replace(/s$/, '') # poor man's singularize options.event_type = type.replace(/s$/, '') # poor man's singularize
@store.find('build', options) @store.query('build', options)
actions: actions:
showMoreBuilds: -> showMoreBuilds: ->

View File

@ -1,9 +1,10 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import Ajax from 'travis/utils/ajax'`
Controller = Ember.Controller.extend Controller = Ember.Controller.extend
needs: ['repo'] ajax: Ember.inject.service()
repo: Ember.computed.alias('controllers.repo.repo')
repoController: Ember.inject.controller('repo')
repo: Ember.computed.alias('repoController.repo')
isDeleting: false isDeleting: false
@ -21,7 +22,7 @@ Controller = Ember.Controller.extend
deletingDone = => @set('isDeleting', false) deletingDone = => @set('isDeleting', false)
repo = @get('repo') repo = @get('repo')
Ajax.ajax("/repos/#{@get('repo.id')}/caches", "DELETE").then(deletingDone, deletingDone).then => @get('ajax').ajax("/repos/#{@get('repo.id')}/caches", "DELETE").then(deletingDone, deletingDone).then =>
@set('model', {}) @set('model', {})
`export default Controller` `export default Controller`

View File

@ -1,48 +0,0 @@
`import Ember from 'ember'`
`import Validations from 'travis/utils/validations'`
Controller = Ember.ObjectController.extend Validations,
isEditing: false
isDeleting: false
validates:
name: ['presence']
actionType: 'Save'
showValueField: Ember.computed.alias('public')
value: ( (key, value) ->
if arguments.length == 2
@get('model').set('value', value)
value
else if @get('public')
@get('model.value')
else
'••••••••••••••••'
).property('model.value', 'public')
actions:
delete: ->
return if @get('isDeleting')
@set('isDeleting', true)
@get('model').destroyRecord()
edit: ->
@set('isEditing', true)
cancel: ->
@set('isEditing', false)
@get('model').revert()
save: ->
return if @get('isSaving')
if @isValid()
env_var = @get('model')
# TODO: handle errors
env_var.save().then =>
@set('isEditing', false)
`export default Controller`

View File

@ -1,6 +0,0 @@
`import Ember from 'ember'`
Controller = Ember.ArrayController.extend
vars: Ember.computed.alias('model')
`export default Controller`

View File

@ -1,45 +0,0 @@
`import Validations from 'travis/utils/validations'`
Controller = Ember.Controller.extend Validations,
needs: ['repo']
repo: Ember.computed.alias('controllers.repo.repo')
isSaving: false
validates:
name: ['presence']
actionType: 'Add'
showValueField: true
reset: ->
@setProperties(name: null, value: null, public: null)
actions:
cancel: ->
@reset()
@transitionToRoute('env_vars')
save: ->
return if @get('isSaving')
@set('isSaving', true)
if @isValid()
env_var = @store.createRecord('env_var',
name: @get('name')
value: @get('value')
public: @get('public')
repo: @get('repo')
)
self = this
env_var.save().then =>
@set('isSaving', false)
@reset()
self.transitionToRoute('env_vars')
, =>
@set('isSaving', false)
else
@set('isSaving', false)
`export default Controller`

View File

@ -1,8 +1,7 @@
`import Ember from 'ember'` `import Ember from 'ember'`
Controller = Ember.Controller.extend Controller = Ember.Controller.extend
needs: ['currentUser'] user: Ember.computed.alias('auth.currentUser')
user: Ember.computed.alias('controllers.currentUser.model')
isSyncing: Ember.computed.alias('user.isSyncing') isSyncing: Ember.computed.alias('user.isSyncing')

View File

@ -2,13 +2,13 @@
`import { githubCommit } from 'travis/utils/urls'` `import { githubCommit } from 'travis/utils/urls'`
Controller = Ember.Controller.extend Controller = Ember.Controller.extend
needs: ['repo', 'currentUser'] repoController: Ember.inject.controller('repo')
repoBinding: 'controllers.repo.repo' repoBinding: 'repoController.repo'
commitBinding: 'job.commit' commitBinding: 'job.commit'
annotationsBinding: 'job.annotations' annotationsBinding: 'job.annotations'
currentUserBinding: 'controllers.currentUser.model' currentUserBinding: 'auth.currentUser'
tabBinding: 'controllers.repo.tab' tabBinding: 'repoController.tab'
currentItemBinding: 'job' currentItemBinding: 'job'

View File

@ -1,5 +1,4 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import Ajax from 'travis/utils/ajax'`
Controller = Ember.Controller.extend Controller = Ember.Controller.extend
isLoading: false isLoading: false

View File

@ -1,5 +1,4 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import Ajax from 'travis/utils/ajax'`
Controller = Ember.Controller.extend Controller = Ember.Controller.extend
isLoading: false isLoading: false
@ -13,14 +12,13 @@ Controller = Ember.Controller.extend
item item
).sortBy('default_branch.last_build.finished_at').reverse() ).sortBy('default_branch.last_build.finished_at').reverse()
repos repos
).property('model') ).property('model')
# running: (-> # running: (->
# data = @get('model') # data = @get('model')
# repos = data.repositories.filter (item, index) -> # repos = data.repositories.filter (item, index) ->
# if item.default_branch.last_build != null # if item.default_branch.last_build != null
# if item.default_branch.last_build.state == 'started' # if item.default_branch.last_build.state == 'started'
# item # item
# repos # repos

View File

@ -1,5 +1,4 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import Ajax from 'travis/utils/ajax'`
Controller = Ember.Controller.extend Controller = Ember.Controller.extend
isLoading: false isLoading: false

View File

@ -3,16 +3,17 @@
Controller = Ember.Controller.extend Controller = Ember.Controller.extend
name: 'profile' name: 'profile'
needs: ['currentUser', 'accounts', 'account'] accountController: Ember.inject.controller('account')
userBinding: 'controllers.currentUser.model' accountsController: Ember.inject.controller('accounts')
accountBinding: 'controllers.account.model' userBinding: 'auth.currentUser'
accountBinding: 'accountController.model'
activate: (action, params) -> activate: (action, params) ->
this["view_#{action}".camelize()]() this["view_#{action}".camelize()]()
viewHooks: -> viewHooks: ->
@connectTab('hooks') @connectTab('hooks')
@get('controllers.account').reloadHooks() @get('accountController').reloadHooks()
viewUser: -> viewUser: ->
@connectTab('user') @connectTab('user')

View File

@ -2,13 +2,15 @@
`import { githubRepo } from 'travis/utils/urls'` `import { githubRepo } from 'travis/utils/urls'`
Controller = Ember.Controller.extend Controller = Ember.Controller.extend
needs: ['repos', 'currentUser', 'build', 'job'] jobController: Ember.inject.controller('job')
currentUserBinding: 'controllers.currentUser.model' buildController: Ember.inject.controller('build')
reposController: Ember.inject.controller('repos')
currentUserBinding: 'auth.currentUser'
classNames: ['repo'] classNames: ['repo']
build: Ember.computed.alias('controllers.build.build') build: Ember.computed.alias('buildController.build')
job: Ember.computed.alias('controllers.job.job') job: Ember.computed.alias('jobController.job')
slug: (-> @get('repo.slug') ).property('repo.slug') slug: (-> @get('repo.slug') ).property('repo.slug')
isLoading: (-> @get('repo.isLoading') ).property('repo.isLoading') isLoading: (-> @get('repo.isLoading') ).property('repo.isLoading')
@ -75,15 +77,15 @@ Controller = Ember.Controller.extend
Ember.run.scheduleOnce('actions', this, @_lastBuildDidChange); Ember.run.scheduleOnce('actions', this, @_lastBuildDidChange);
_lastBuildDidChange: -> _lastBuildDidChange: ->
build = @get('repo.lastBuild') build = @get('repo.defaultBranch.lastBuild')
@set('build', build) @set('build', build)
stopObservingLastBuild: -> stopObservingLastBuild: ->
@removeObserver('repo.lastBuild', this, 'lastBuildDidChange') @removeObserver('repo.defaultBranch.lastBuild', this, 'lastBuildDidChange')
observeLastBuild: -> observeLastBuild: ->
@lastBuildDidChange() @lastBuildDidChange()
@addObserver('repo.lastBuild', this, 'lastBuildDidChange') @addObserver('repo.defaultBranch.lastBuild', this, 'lastBuildDidChange')
connectTab: (tab) -> connectTab: (tab) ->
# TODO: such implementation seems weird now, because we render # TODO: such implementation seems weird now, because we render

View File

@ -1,132 +0,0 @@
`import Ember from 'ember'`
`import limit from 'travis/utils/computed-limit'`
`import Repo from 'travis/models/repo'`
Controller = Ember.Controller.extend
contentBinding: 'repos'
actions:
activate: (name) ->
@activate(name)
showRunningJobs: ->
@activate('running')
showMyRepositories: ->
# this is a bit of a hack. I don't want to switch URL for 'running'
# so depending on current state I'm either just switching back or
# redirecting
if @get('tab') == 'running'
@activate('owned')
else
@transitionToRoute('main.repositories')
tabOrIsLoadedDidChange: (->
@possiblyRedirectToGettingStartedPage()
).observes('isLoaded', 'tab', 'repos.length')
possiblyRedirectToGettingStartedPage: ->
Ember.run.scheduleOnce 'routerTransitions', this, ->
if @get('tab') == 'owned' && @get('isLoaded') && @get('repos.length') == 0
@container.lookup('router:main').send('redirectToGettingStarted')
isLoadedBinding: 'repos.isLoaded'
needs: ['currentUser', 'repo']
currentUserBinding: 'controllers.currentUser.model'
selectedRepo: (->
# we need to observe also repo.content here, because we use
# ObjectProxy in repo controller
# TODO: get rid of ObjectProxy there
@get('controllers.repo.repo.content') || @get('controllers.repo.repo')
).property('controllers.repo.repo', 'controllers.repo.repo.content')
startedJobsCount: Ember.computed.alias('runningJobs.length')
allJobsCount: (->
@get('startedJobsCount') + @get('queuedJobs.length')
).property('startedJobsCount', 'queuedJobs.length')
init: ->
@_super.apply this, arguments
if !Ember.testing
Visibility.every @config.intervals.updateTimes, @updateTimes.bind(this)
runningJobs: (->
result = @store.filter('job', {}, (job) ->
['queued', 'started', 'received'].indexOf(job.get('state')) != -1
)
result.set('isLoaded', false)
result.then =>
result.set('isLoaded', true)
result
).property()
queuedJobs: (->
result = @get('store').filter('job', {}, (job) ->
['created'].indexOf(job.get('state')) != -1
)
result.set('isLoaded', false)
result.then =>
result.set('isLoaded', true)
result
).property()
recentRepos: (->
# I return an empty array here, because we're removing left sidebar, but
# I don't want to refactor too much code (it will be all changed anyway
# when we switch to new dashboard)
[]
).property()
updateTimes: ->
if repos = @get('repos')
repos.forEach (r) -> r.updateTimes()
activate: (tab, params) ->
@set('sortProperties', ['sortOrder'])
@set('tab', tab)
this["view_#{tab}".camelize()](params)
viewOwned: ->
@set('repos', @get('userRepos'))
viewRunning: ->
userRepos: (->
if login = @get('currentUser.login')
Repo.accessibleBy(@store, login)
else
[]
).property('currentUser.login')
viewSearch: (phrase) ->
@set('search', phrase)
@set('repos', Repo.search(@store, phrase))
searchObserver: (->
search = @get('search')
if search
@searchFor search
).observes('search')
searchFor: (phrase) ->
Ember.run.cancel(@searchLater) if @searchLater
@searchLater = Ember.run.later(this, (->
@transitionTo('main.search', phrase.replace(/\//g, '%2F'))
), 500)
noReposMessage: (->
tab = @get('tab')
if tab == 'owned'
'You don\'t have any repos set up on Travis CI'
else if tab == 'recent'
'Repositories could not be loaded'
else
'Could not find any repos'
).property('tab')
showRunningJobs: (->
@get('tab') == 'running'
).property('tab')
`export default Controller`

234
app/controllers/repos.js Normal file
View File

@ -0,0 +1,234 @@
import Ember from 'ember';
import limit from 'travis/utils/computed-limit';
import Repo from 'travis/models/repo';
var sortCallback = function(repo1, repo2) {
// this function could be made simpler, but I think it's clearer this way
// what're we really trying to achieve
var lastBuild1 = repo1.get('defaultBranch.lastBuild');
var lastBuild2 = repo2.get('defaultBranch.lastBuild');
if(!lastBuild1 && !lastBuild2) {
// if both repos lack builds, put newer repo first
return repo1.get('id') > repo2.get('id') ? -1 : 1;
} else if(lastBuild1 && !lastBuild2) {
// if only repo1 has a build, it goes first
return -1;
} else if(lastBuild2 && !lastBuild1) {
// if only repo2 has a build, it goes first
return 1;
}
var finishedAt1 = lastBuild1.get('finishedAt');
var finishedAt2 = lastBuild2.get('finishedAt');
if(finishedAt1) {
finishedAt1 = new Date(finishedAt1);
}
if(finishedAt2) {
finishedAt2 = new Date(finishedAt2);
}
if(finishedAt1 && finishedAt2) {
// if both builds finished, put newer first
return finishedAt1.getTime() > finishedAt2.getTime() ? -1 : 1;
} else if(finishedAt1 && !finishedAt2) {
// if repo1 finished, but repo2 didn't, put repo2 first
return 1;
} else if(finishedAt2 && !finishedAt1) {
// if repo2 finisher, but repo1 didn't, put repo1 first
return -1;
} else {
// none of the builds finished, put newer build first
return lastBuild1.get('id') > lastBuild2.get('id') ? -1 : 1;
}
throw "should not happen";
};
var Controller = Ember.Controller.extend({
ajax: Ember.inject.service(),
actions: {
activate: function(name) {
return this.activate(name);
},
showRunningJobs: function() {
return this.activate('running');
},
showMyRepositories: function() {
if (this.get('tab') === 'running') {
return this.activate('owned');
} else {
return this.transitionToRoute('main.repositories');
}
}
},
tabOrIsLoadedDidChange: function() {
return this.possiblyRedirectToGettingStartedPage();
}.observes('isLoaded', 'tab', 'repos.length'),
possiblyRedirectToGettingStartedPage() {
return Ember.run.scheduleOnce('routerTransitions', this, function() {
if (this.get('tab') === 'owned' && this.get('isLoaded') && this.get('repos.length') === 0) {
return this.container.lookup('router:main').send('redirectToGettingStarted');
}
});
},
isLoaded: false,
repoController: Ember.inject.controller('repo'),
currentUserBinding: 'auth.currentUser',
selectedRepo: function() {
return this.get('repoController.repo.content') || this.get('repoController.repo');
}.property('repoController.repo', 'repoController.repo.content'),
startedJobsCount: Ember.computed.alias('runningJobs.length'),
allJobsCount: function() {
return this.get('startedJobsCount') + this.get('queuedJobs.length');
}.property('startedJobsCount', 'queuedJobs.length'),
init() {
this._super.apply(this, arguments);
if (!Ember.testing) {
return Visibility.every(this.config.intervals.updateTimes, this.updateTimes.bind(this));
}
},
runningJobs: function() {
var result;
result = this.store.filter('job', {}, function(job) {
return ['queued', 'started', 'received'].indexOf(job.get('state')) !== -1;
});
result.set('isLoaded', false);
result.then(function() {
return result.set('isLoaded', true);
});
return result;
}.property(),
queuedJobs: function() {
var result;
result = this.get('store').filter('job', {}, function(job) {
return ['created'].indexOf(job.get('state')) !== -1;
});
result.set('isLoaded', false);
result.then(function() {
result.set('isLoaded', true);
});
return result;
}.property(),
recentRepos: function() {
return [];
}.property(),
updateTimes() {
var repos;
if (repos = this.get('repos')) {
return repos.forEach(function(r) {
return r.updateTimes();
});
}
},
activate(tab, params) {
this.set('sortProperties', ['sortOrder']);
this.set('tab', tab);
return this[("view_" + tab).camelize()](params);
},
viewOwned() {
var repos, user;
if (repos = this.get('ownedRepos')) {
return this.set('_repos', repos);
} else if (!this.get('fetchingOwnedRepos')) {
this.set('fetchingOwnedRepos', true);
this.set('isLoaded', false);
if (user = this.get('currentUser')) {
user.get('_rawPermissions').then( (data) => {
repos = Repo.accessibleBy(this.store, data.pull).then(
(reposRecordArray) => {
this.set('isLoaded', true);
this.set('_repos', reposRecordArray);
this.set('ownedRepos', reposRecordArray);
this.set('fetchingOwnedRepos', false);
return reposRecordArray;
});
});
}
}
},
viewRunning() {},
viewSearch(phrase) {
this.set('search', phrase);
this.set('isLoaded', false);
Repo.search(this.store, this.get('ajax'), phrase).then( (reposRecordArray) => {
this.set('isLoaded', true);
this.set('_repos', reposRecordArray);
});
},
searchObserver: function() {
var search;
search = this.get('search');
if (search) {
return this.searchFor(search);
}
}.observes('search'),
searchFor(phrase) {
if (this.searchLater) {
Ember.run.cancel(this.searchLater);
}
this.searchLater = Ember.run.later(this, (function() {
this.transitionTo('main.search', phrase.replace(/\//g, '%2F'));
}), 500);
},
noReposMessage: function() {
var tab;
tab = this.get('tab');
if (tab === 'owned') {
return 'You don\'t have any repos set up on Travis CI';
} else if (tab === 'recent') {
return 'Repositories could not be loaded';
} else {
return 'Could not find any repos';
}
}.property('tab'),
showRunningJobs: function() {
return this.get('tab') === 'running';
}.property('tab'),
repos: function() {
var repos = this.get('_repos');
if(repos && repos.toArray) {
repos = repos.toArray();
}
if(repos && repos.sort) {
return repos.sort(sortCallback);
} else {
return [];
}
}.property('_repos.[]', '_repos.@each.lastBuildFinishedAt',
'_repos.@each.lastBuildId')
});
export default Controller;

View File

@ -1,12 +1,11 @@
`import Ember from 'ember'` `import Ember from 'ember'`
Controller = Ember.ArrayController.extend Controller = Ember.ArrayController.extend
needs: ['repo'] repoController: Ember.inject.controller('repo')
repo: Ember.computed.alias('controllers.repo.repo')
lintUrl: (-> lintUrl: (->
slug = @get('repo.slug') slug = @get('repoController.repo.slug')
"https://lint.travis-ci.org/#{slug}" "https://lint.travis-ci.org/#{slug}"
).property('repo.slug') ).property('repoController.repo.slug')
`export default Controller` `export default Controller`

View File

@ -1,22 +0,0 @@
`import Ember from 'ember'`
Controller = Ember.Controller.extend
settings: Ember.computed.alias('model.settings')
settingsChanged: (->
value = @get('settings.maximum_number_of_builds')
console.log value
if parseInt(value) > 0 || value == '0' || value == 0
@set('settings.maximum_number_of_builds_valid', '')
@get('model').saveSettings(@get('settings')).then null, ->
Travis.flash(error: 'There was an error while saving settings. Please try again.')
else
@set('settings.maximum_number_of_builds_valid', 'invalid')
).observes('settings.maximum_number_of_builds')
actions:
save: ->
@get('model').saveSettings(@get('settings')).then null, ->
Travis.flash(error: 'There was an error while saving settings. Please try again.')
`export default Controller`

View File

@ -1,12 +1,11 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import Ajax from 'travis/utils/ajax'`
`import config from 'travis/config/environment'` `import config from 'travis/config/environment'`
Controller = Ember.Controller.extend Controller = Ember.Controller.extend
needs: ['currentUser'] userBinding: 'auth.currentUser'
userBinding: 'controllers.currentUser.model'
store: Ember.inject.service() store: Ember.inject.service()
storage: Ember.inject.service()
currentUserBinding: 'auth.currentUser' currentUserBinding: 'auth.currentUser'
userName: (-> userName: (->
@ -18,6 +17,8 @@ Controller = Ember.Controller.extend
).property('user.gravatarId') ).property('user.gravatarId')
defineTowerColor: (broadcastArray) -> defineTowerColor: (broadcastArray) ->
return '' unless broadcastArray
if broadcastArray.length if broadcastArray.length
if broadcastArray.findBy('category', 'warning') if broadcastArray.findBy('category', 'warning')
return 'warning' return 'warning'
@ -39,7 +40,7 @@ Controller = Ember.Controller.extend
options.type = 'GET' options.type = 'GET'
options.headers = { Authorization: "token #{@auth.token()}" } options.headers = { Authorization: "token #{@auth.token()}" }
seenBroadcasts = Travis.storage.getItem('travis.seen_broadcasts') seenBroadcasts = @get('storage').getItem('travis.seen_broadcasts')
if seenBroadcasts if seenBroadcasts
seenBroadcasts = JSON.parse(seenBroadcasts) seenBroadcasts = JSON.parse(seenBroadcasts)
else else
@ -73,13 +74,13 @@ Controller = Ember.Controller.extend
markBroadcastAsSeen: (broadcast) -> markBroadcastAsSeen: (broadcast) ->
id = broadcast.get('id').toString() id = broadcast.get('id').toString()
seenBroadcasts = Travis.storage.getItem('travis.seen_broadcasts') seenBroadcasts = @get('storage').getItem('travis.seen_broadcasts')
if seenBroadcasts if seenBroadcasts
seenBroadcasts = JSON.parse(seenBroadcasts) seenBroadcasts = JSON.parse(seenBroadcasts)
else else
seenBroadcasts = [] seenBroadcasts = []
seenBroadcasts.push(id) seenBroadcasts.push(id)
Travis.storage.setItem('travis.seen_broadcasts', JSON.stringify(seenBroadcasts)) @get('storage').setItem('travis.seen_broadcasts', JSON.stringify(seenBroadcasts))
@get('broadcasts.content').removeObject(broadcast) @get('broadcasts.content').removeObject(broadcast)
@set('broadcasts.lastBroadcastStatus', @defineTowerColor(@get('broadcasts.content'))) @set('broadcasts.lastBroadcastStatus', @defineTowerColor(@get('broadcasts.content')))
return false return false

View File

@ -1,6 +1,6 @@
`import { safe, formatCommit as formatCommitHelper } from 'travis/utils/helpers'` `import { safe, formatCommit as formatCommitHelper } from 'travis/utils/helpers'`
helper = Ember.HTMLBars.makeBoundHelper (params) -> helper = Ember.Helper.helper (params) ->
commit = params[0] commit = params[0]
safe formatCommitHelper(commit.get('sha'), commit.get('branch')) if commit safe formatCommitHelper(commit.get('sha'), commit.get('branch')) if commit

View File

@ -1,7 +1,7 @@
`import { timeInWords, safe } from 'travis/utils/helpers'` `import { timeInWords, safe } from 'travis/utils/helpers'`
`import Ember from "ember"` `import Ember from "ember"`
helper = Ember.HTMLBars.makeBoundHelper (params) -> helper = Ember.Helper.helper (params) ->
safe timeInWords(params[0]) safe timeInWords(params[0])
`export default helper` `export default helper`

View File

@ -1,7 +1,7 @@
`import { formatMessage as _formatMessage, safe } from 'travis/utils/helpers'` `import { formatMessage as _formatMessage, safe } from 'travis/utils/helpers'`
`import Ember from "ember"` `import Ember from "ember"`
helper = Ember.HTMLBars.makeBoundHelper (params, hash) -> helper = Ember.Helper.helper (params, hash) ->
safe _formatMessage(params[0], hash) safe _formatMessage(params[0], hash)
`export default helper` `export default helper`

View File

@ -1,7 +1,7 @@
`import { formatSha as _formatSha, safe } from 'travis/utils/helpers'` `import { formatSha as _formatSha, safe } from 'travis/utils/helpers'`
`import Ember from "ember"` `import Ember from "ember"`
helper = Ember.HTMLBars.makeBoundHelper (params) -> helper = Ember.Helper.helper (params) ->
safe _formatSha(params[0]) safe _formatSha(params[0])
`export default helper` `export default helper`

View File

@ -1,7 +1,7 @@
`import { timeAgoInWords, safe } from 'travis/utils/helpers'` `import { timeAgoInWords, safe } from 'travis/utils/helpers'`
`import Ember from "ember"` `import Ember from "ember"`
helper = Ember.HTMLBars.makeBoundHelper (params) -> helper = Ember.Helper.helper (params) ->
safe timeAgoInWords(params[0]) || '-' safe timeAgoInWords(params[0]) || '-'
`export default helper` `export default helper`

View File

@ -1,7 +1,7 @@
`import { formatCommit, safe } from 'travis/utils/helpers'` `import { formatCommit, safe } from 'travis/utils/helpers'`
`import { githubCommit as githubCommitUrl } from 'travis/utils/urls'` `import { githubCommit as githubCommitUrl } from 'travis/utils/urls'`
helper = Ember.HTMLBars.makeBoundHelper (params) -> helper = Ember.Helper.helper (params) ->
slug = params[0] slug = params[0]
commitSha = params[1] commitSha = params[1]
return '' unless commitSha return '' unless commitSha

View File

@ -1,7 +1,7 @@
`import { safe } from 'travis/utils/helpers'` `import { safe } from 'travis/utils/helpers'`
`import Ember from "ember"` `import Ember from "ember"`
helper = Ember.HTMLBars.makeBoundHelper (params) -> helper = Ember.Helper.helper (params) ->
state = params[0] state = params[0]
if state == 'received' if state == 'received'
'booting' 'booting'

View File

@ -1,7 +1,7 @@
`import { timeAgoInWords, safe } from 'travis/utils/helpers'` `import { timeAgoInWords, safe } from 'travis/utils/helpers'`
`import Ember from "ember"` `import Ember from "ember"`
helper = Ember.HTMLBars.makeBoundHelper (params) -> helper = Ember.Helper.helper (params) ->
safe timeAgoInWords(params[0]) || 'currently running' safe timeAgoInWords(params[0]) || 'currently running'
`export default helper` `export default helper`

View File

@ -1,7 +1,7 @@
`import { timeAgoInWords, safe } from 'travis/utils/helpers'` `import { timeAgoInWords, safe } from 'travis/utils/helpers'`
`import Ember from "ember"` `import Ember from "ember"`
helper = Ember.HTMLBars.makeBoundHelper (params) -> helper = Ember.Helper.helper (params) ->
safe moment(params[0]).format('MMMM D, YYYY H:mm:ss') || '-' safe moment(params[0]).format('MMMM D, YYYY H:mm:ss') || '-'
`export default helper` `export default helper`

View File

@ -1,7 +1,7 @@
`import { pathFrom } from 'travis/utils/helpers'` `import { pathFrom } from 'travis/utils/helpers'`
`import Ember from "ember"` `import Ember from "ember"`
helper = Ember.HTMLBars.makeBoundHelper (params) -> helper = Ember.Helper.helper (params) ->
url = params[0] url = params[0]
path = pathFrom(url) path = pathFrom(url)
if path.indexOf('...') >= 0 if path.indexOf('...') >= 0

View File

@ -4,4 +4,4 @@ fn = (size) ->
if size if size
(size / 1024 / 1024).toFixed(2) (size / 1024 / 1024).toFixed(2)
`export default Ember.HTMLBars.makeBoundHelper(fn)` `export default Ember.Helper.helper(fn)`

View File

@ -1,16 +1,11 @@
`import Auth from 'travis/utils/auth'`
`import TestAuth from 'travis/utils/test-auth'` `import TestAuth from 'travis/utils/test-auth'`
initialize = (container, app) -> initialize = (container, app) ->
app.register 'auth:main', if Ember.testing then TestAuth else Auth app.inject('route', 'auth', 'service:auth')
app.inject('controller', 'auth', 'service:auth')
app.inject('route', 'auth', 'auth:main') app.inject('application', 'auth', 'service:auth')
app.inject('controller', 'auth', 'auth:main') app.inject('component', 'auth', 'service:auth')
app.inject('application', 'auth', 'auth:main') app.inject('service:flashes', 'auth', 'service:auth')
app.inject('component', 'auth', 'auth:main')
app.inject('service:flashes', 'auth', 'auth:main')
app.inject('auth', 'store', 'service:store')
AuthInitializer = AuthInitializer =
name: 'auth' name: 'auth'

View File

@ -2,12 +2,7 @@
`import TravisPusher from 'travis/utils/pusher'` `import TravisPusher from 'travis/utils/pusher'`
initialize = (registry, application) -> initialize = (registry, application) ->
if config.pusher.key null
application.pusher = new TravisPusher(config.pusher)
application.register 'pusher:main', application.pusher, { instantiate: false }
application.inject('route', 'pusher', 'pusher:main')
PusherInitializer = PusherInitializer =
name: 'pusher' name: 'pusher'

View File

@ -1,16 +1,11 @@
`import Slider from 'travis/utils/slider'`
`import Tailing from 'travis/utils/tailing'` `import Tailing from 'travis/utils/tailing'`
`import ToTop from 'travis/utils/to-top'` `import ToTop from 'travis/utils/to-top'`
`import config from 'travis/config/environment'` `import config from 'travis/config/environment'`
initialize = (container, application) -> initialize = (container, application) ->
application.slider = new Slider(application.storage)
application.tailing = new Tailing($(window), '#tail', '#log') application.tailing = new Tailing($(window), '#tail', '#log')
application.toTop = new ToTop($(window), '.to-top', '#log-container') application.toTop = new ToTop($(window), '.to-top', '#log-container')
application.register 'slider:main', application.slider, { instantiate: false }
application.inject('controller', 'slider', 'slider:main')
Initializer = Initializer =
name: 'services' name: 'services'
initialize: initialize initialize: initialize

View File

@ -1,58 +0,0 @@
`import Ember from 'ember'`
Storage = Em.Object.extend
init: ->
@set('storage', {})
key: (key) ->
"__#{key.replace('.', '__')}"
getItem: (k) ->
return @get("storage.#{@key(k)}")
setItem: (k,v) ->
@set("storage.#{@key(k)}", v)
removeItem: (k) ->
@setItem(k, null)
clear: ->
@set('storage', {})
sessionStorage = (->
storage = null
try
# firefox will not throw error on access for sessionStorage var,
# you need to actually get something from session
window.sessionStorage.getItem('foo')
storage = window.sessionStorage
catch err
storage = Storage.create()
storage
)()
storage = (->
storage = null
try
storage = window.localStorage || throw('no storage')
catch err
storage = Storage.create()
storage
)()
initialize = (container, application) ->
application.register 'storage:main', storage, { instantiate: false }
application.register 'sessionStorage:main', sessionStorage, { instantiate: false }
application.inject('auth', 'storage', 'storage:main')
application.inject('auth', 'sessionStorage', 'sessionStorage:main')
# I still use Travis.storage in some places which are not that easy to
# refactor
application.storage = storage
application.sessionStorage = sessionStorage
StorageInitializer =
name: 'storage'
before: 'services'
initialize: initialize
`export {initialize}`
`export default StorageInitializer`

View File

@ -1,5 +1,17 @@
`import config from 'travis/config/environment'`
`import TravisPusher from 'travis/utils/pusher'`
initialize = (data) -> initialize = (data) ->
data.application.pusher.store = data.container.lookup('service:store') application = data.application
if config.pusher.key
application.pusher = new TravisPusher(config.pusher, data.container.lookup('service:ajax'))
application.register 'pusher:main', application.pusher, { instantiate: false }
application.inject('route', 'pusher', 'pusher:main')
application.pusher.store = data.container.lookup('service:store')
PusherInitializer = PusherInitializer =
name: 'pusher' name: 'pusher'

View File

@ -2,25 +2,11 @@
`import Model from 'travis/models/model'` `import Model from 'travis/models/model'`
Branch = Model.extend Branch = Model.extend
repositoryId: DS.attr('number') name: DS.attr('string')
commitId: DS.attr('number') defaultBranch: DS.attr('boolean')
state: DS.attr()
number: DS.attr('number')
branch: DS.attr()
message: DS.attr()
result: DS.attr('number')
duration: DS.attr('number')
startedAt: DS.attr()
finishedAt: DS.attr()
commit: DS.belongsTo('commit') lastBuild: DS.belongsTo('build')
builds: DS.hasMany('builds', inverse: 'branch')
repo: (-> repo: DS.belongsTo('repo', inverse: 'defaultBranch')
@store.find('repo', @get('repositoryId')) if @get('repositoryId')
).property('repositoryId')
updateTimes: ->
@notifyPropertyChange 'started_at'
@notifyPropertyChange 'finished_at'
`export default Branch` `export default Branch`

View File

@ -18,7 +18,7 @@ Broadcast = Model.extend
Broadcast.reopenClass Broadcast.reopenClass
seen: (-> seen: (->
seenBroadcasts = Travis.storage.getItem('travis.seen_broadcasts') seenBroadcasts = Travis.lookup('service:storage').getItem('travis.seen_broadcasts')
seenBroadcasts = JSON.parse(seenBroadcasts) if seenBroadcasts? seenBroadcasts = JSON.parse(seenBroadcasts) if seenBroadcasts?
Ember.A(seenBroadcasts || []) Ember.A(seenBroadcasts || [])
).property() ).property()

View File

@ -1,26 +1,28 @@
`import { durationFrom, configKeys, compact } from 'travis/utils/helpers'` `import { durationFrom, configKeys, compact } from 'travis/utils/helpers'`
`import Ajax from 'travis/utils/ajax'`
`import configKeysMap from 'travis/utils/keys-map'` `import configKeysMap from 'travis/utils/keys-map'`
`import Ember from 'ember'` `import Ember from 'ember'`
`import Model from 'travis/models/model'` `import Model from 'travis/models/model'`
`import DurationCalculations from 'travis/utils/duration-calculations'` `import DurationCalculations from 'travis/utils/duration-calculations'`
Build = Model.extend DurationCalculations, Build = Model.extend DurationCalculations,
ajax: Ember.inject.service()
state: DS.attr() state: DS.attr()
number: DS.attr('number') number: DS.attr('number')
branch: DS.attr('string')
message: DS.attr('string') message: DS.attr('string')
_duration: DS.attr('number') _duration: DS.attr('number')
_config: DS.attr('object') _config: DS.attr('object')
_startedAt: DS.attr() _startedAt: DS.attr()
_finishedAt: DS.attr() _finishedAt: DS.attr('string')
pullRequest: DS.attr('boolean') pullRequest: DS.attr('boolean')
pullRequestTitle: DS.attr() pullRequestTitle: DS.attr()
pullRequestNumber: DS.attr('number') pullRequestNumber: DS.attr('number')
eventType: DS.attr('string') eventType: DS.attr('string')
repositoryId: DS.attr('number')
branch: DS.belongsTo('branch', async: false, inverse: 'builds')
repo: DS.belongsTo('repo', async: true) repo: DS.belongsTo('repo', async: true)
commit: DS.belongsTo('commit', async: true) commit: DS.belongsTo('commit', async: false)
jobs: DS.hasMany('job', async: true) jobs: DS.hasMany('job', async: true)
config: (-> config: (->
@ -90,11 +92,11 @@ Build = Model.extend DurationCalculations,
canRestart: Ember.computed.alias('isFinished') canRestart: Ember.computed.alias('isFinished')
cancel: (-> cancel: (->
Ajax.post "/builds/#{@get('id')}/cancel" @get('ajax').post "/builds/#{@get('id')}/cancel"
) )
restart: -> restart: ->
Ajax.post "/builds/#{@get('id')}/restart" @get('ajax').post "/builds/#{@get('id')}/restart"
formattedFinishedAt: (-> formattedFinishedAt: (->
if finishedAt = @get('finishedAt') if finishedAt = @get('finishedAt')

View File

@ -1,5 +1,4 @@
`import { durationFrom, configKeys, compact } from 'travis/utils/helpers'` `import { durationFrom, configKeys, compact } from 'travis/utils/helpers'`
`import Ajax from 'travis/utils/ajax'`
`import configKeysMap from 'travis/utils/keys-map'` `import configKeysMap from 'travis/utils/keys-map'`
`import Ember from 'ember'` `import Ember from 'ember'`
`import Model from 'travis/models/model'` `import Model from 'travis/models/model'`
@ -7,6 +6,7 @@
`import DurationCalculations from 'travis/utils/duration-calculations'` `import DurationCalculations from 'travis/utils/duration-calculations'`
Job = Model.extend DurationCalculations, Job = Model.extend DurationCalculations,
ajax: Ember.inject.service()
logId: DS.attr() logId: DS.attr()
queue: DS.attr() queue: DS.attr()
@ -24,13 +24,15 @@ Job = Model.extend DurationCalculations,
build: DS.belongsTo('build', async: true) build: DS.belongsTo('build', async: true)
commit: DS.belongsTo('commit', async: true) commit: DS.belongsTo('commit', async: true)
branch: Ember.computed.alias('build.branch')
annotations: DS.hasMany('annotation') annotations: DS.hasMany('annotation')
_config: DS.attr('object') _config: DS.attr('object')
log: ( -> log: ( ->
@set('isLogAccessed', true) @set('isLogAccessed', true)
Log.create(job: this) Log.create(job: this, ajax: @get('ajax'))
).property() ).property()
startedAt: (-> startedAt: (->
@ -94,11 +96,11 @@ Job = Model.extend DurationCalculations,
canRestart: Ember.computed.alias('isFinished') canRestart: Ember.computed.alias('isFinished')
cancel: (-> cancel: (->
Ajax.post "/jobs/#{@get('id')}/cancel" @get('ajax').post "/jobs/#{@get('id')}/cancel"
) )
removeLog: -> removeLog: ->
Ajax.patch("/jobs/#{@get('id')}/log").then => @get('ajax').patch("/jobs/#{@get('id')}/log").then =>
@reloadLog() @reloadLog()
reloadLog: -> reloadLog: ->
@ -106,7 +108,7 @@ Job = Model.extend DurationCalculations,
@get('log').fetch() @get('log').fetch()
restart: -> restart: ->
Ajax.post "/jobs/#{@get('id')}/restart" @get('ajax').post "/jobs/#{@get('id')}/restart"
appendLog: (part) -> appendLog: (part) ->
@get('log').append part @get('log').append part

View File

@ -1,5 +1,4 @@
`import Model from 'travis/models/model'` `import Model from 'travis/models/model'`
`import Ajax from 'travis/utils/ajax'`
`import Job from 'travis/models/job'` `import Job from 'travis/models/job'`
`import Ember from 'ember'` `import Ember from 'ember'`
`import config from 'travis/config/environment'` `import config from 'travis/config/environment'`
@ -9,7 +8,7 @@ Request = Ember.Object.extend
accept: 'application/json; chunked=true; version=2, text/plain; version=2' accept: 'application/json; chunked=true; version=2, text/plain; version=2'
run: -> run: ->
Ajax.ajax "/jobs/#{@id}/log?cors_hax=true", 'GET', @get('ajax').ajax "/jobs/#{@id}/log?cors_hax=true", 'GET',
dataType: 'text' dataType: 'text'
headers: @HEADERS headers: @HEADERS
success: (body, status, xhr) => Ember.run(this, -> @handle(body, status, xhr)) success: (body, status, xhr) => Ember.run(this, -> @handle(body, status, xhr))
@ -50,7 +49,7 @@ Log = Ember.Object.extend
data['part_numbers'] = partNumbers if partNumbers data['part_numbers'] = partNumbers if partNumbers
data['after'] = after if after data['after'] = after if after
Ajax.ajax "/jobs/#{@get('job.id')}/log", 'GET', @get('ajax').ajax "/jobs/#{@get('job.id')}/log", 'GET',
dataType: 'json' dataType: 'json'
headers: headers:
accept: 'application/json; chunked=true; version=2' accept: 'application/json; chunked=true; version=2'
@ -81,7 +80,8 @@ Log = Ember.Object.extend
@set('removed', true) @set('removed', true)
@loadParts(json['log']['parts']) @loadParts(json['log']['parts'])
text: (text) => @loadText(text) text: (text) => @loadText(text)
Request.create(id: id, handlers: handlers, log: this).run() if id = @get('job.id') if id = @get('job.id')
Request.create(id: id, handlers: handlers, log: this, ajax: @get('ajax')).run()
clear: -> clear: ->
@clearParts() @clearParts()

View File

@ -1,40 +1,28 @@
`import ExpandableRecordArray from 'travis/utils/expandable-record-array'` `import ExpandableRecordArray from 'travis/utils/expandable-record-array'`
`import Model from 'travis/models/model'` `import Model from 'travis/models/model'`
`import Ajax from 'travis/utils/ajax'`
# TODO: Investigate for some weird reason if I use durationFrom here not durationFromHelper, # TODO: Investigate for some weird reason if I use durationFrom here not durationFromHelper,
# the function stops being visible inside computed properties. # the function stops being visible inside computed properties.
`import { durationFrom as durationFromHelper } from 'travis/utils/helpers'` `import { durationFrom as durationFromHelper } from 'travis/utils/helpers'`
`import Build from 'travis/models/build'` `import Build from 'travis/models/build'`
Repo = Model.extend Repo = Model.extend
ajax: Ember.inject.service()
slug: DS.attr() slug: DS.attr()
description: DS.attr() description: DS.attr()
private: DS.attr('boolean') private: DS.attr('boolean')
lastBuildNumber: DS.attr('number')
lastBuildState: DS.attr()
lastBuildStartedAt: DS.attr()
lastBuildFinishedAt: DS.attr()
githubLanguage: DS.attr() githubLanguage: DS.attr()
_lastBuildDuration: DS.attr('number')
lastBuildLanguage: DS.attr()
active: DS.attr() active: DS.attr()
lastBuildId: DS.attr('number')
lastBuildHash: (->
{
id: @get('lastBuildId')
number: @get('lastBuildNumber')
repo: this
}
).property('lastBuildId', 'lastBuildNumber')
lastBuild: (-> #lastBuild: DS.belongsTo('build')
if id = @get('lastBuildId') defaultBranch: DS.belongsTo('branch', async: false)
@store.find('build', id)
@store.recordForId('build', id) # just for sorting
).property('lastBuildId') lastBuildFinishedAt: Ember.computed.oneWay('defaultBranch.lastBuild.finishedAt')
lastBuildId: Ember.computed.oneWay('defaultBranch.lastBuild.id')
withLastBuild: -> withLastBuild: ->
@filter( (repo) -> repo.get('lastBuildId') ) @filter( (repo) -> repo.get('defaultBranch.lastBuild') )
sshKey: (-> sshKey: (->
@store.find('ssh_key', @get('id')) @store.find('ssh_key', @get('id'))
@ -51,7 +39,7 @@ Repo = Model.extend
builds: (-> builds: (->
id = @get('id') id = @get('id')
builds = @store.filter('build', event_type: ['push', 'api'], repository_id: id, (b) -> builds = @store.filter('build', event_type: ['push', 'api'], repository_id: id, (b) ->
b.get('repo.id') == id && (b.get('eventType') == 'push' || b.get('eventType') == 'api') b.get('repositoryId')+'' == id+'' && (b.get('eventType') == 'push' || b.get('eventType') == 'api')
) )
# TODO: move to controller # TODO: move to controller
@ -68,7 +56,7 @@ Repo = Model.extend
pullRequests: (-> pullRequests: (->
id = @get('id') id = @get('id')
builds = @store.filter('build', event_type: 'pull_request', repository_id: id, (b) -> builds = @store.filter('build', event_type: 'pull_request', repository_id: id, (b) ->
b.get('repo.id') == id && b.get('eventType') == 'pull_request' b.get('repositoryId')+'' == id+'' && b.get('eventType') == 'pull_request'
) )
# TODO: move to controller # TODO: move to controller
@ -85,7 +73,7 @@ Repo = Model.extend
).property() ).property()
branches: (-> branches: (->
builds = @store.find 'build', repository_id: @get('id'), branches: true builds = @store.query 'build', repository_id: @get('id'), branches: true
builds.then -> builds.then ->
builds.set 'isLoaded', true builds.set 'isLoaded', true
@ -101,27 +89,13 @@ Repo = Model.extend
(@get('slug') || '').split('/')[1] (@get('slug') || '').split('/')[1]
).property('slug') ).property('slug')
lastBuildDuration: (->
duration = @get('_lastBuildDuration')
duration = durationFromHelper(@get('lastBuildStartedAt'), @get('lastBuildFinishedAt')) unless duration
duration
).property('_lastBuildDuration', 'lastBuildStartedAt', 'lastBuildFinishedAt')
sortOrderForLandingPage: (-> sortOrderForLandingPage: (->
state = @get('lastBuildState') state = @get('defaultBranch.lastBuild.state')
if state != 'passed' && state != 'failed' if state != 'passed' && state != 'failed'
0 0
else else
parseInt(@get('lastBuildId')) parseInt(@get('defaultBranch.lastBuild.id'))
).property('lastBuildId', 'lastBuildState') ).property('defaultBranch.lastBuild.id', 'defaultBranch.lastBuild.state')
sortOrder: (->
# cuz sortAscending seems buggy when set to false
if lastBuildFinishedAt = @get('lastBuildFinishedAt')
- new Date(lastBuildFinishedAt).getTime()
else
- new Date('9999').getTime() - parseInt(@get('lastBuildId'))
).property('lastBuildFinishedAt', 'lastBuildId')
stats: (-> stats: (->
if @get('slug') if @get('slug')
@ -132,43 +106,58 @@ Repo = Model.extend
).property('slug') ).property('slug')
updateTimes: -> updateTimes: ->
@notifyPropertyChange 'lastBuildDuration' if lastBuild = @get('defaultBranch.lastBuild')
lastBuild.updateTimes()
regenerateKey: (options) -> regenerateKey: (options) ->
Ajax.ajax '/repos/' + @get('id') + '/key', 'post', options @get('ajax').ajax '/repos/' + @get('id') + '/key', 'post', options
fetchSettings: -> fetchSettings: ->
Ajax.ajax('/repos/' + @get('id') + '/settings', 'get', forceAuth: true).then (data) -> @get('ajax').ajax('/repos/' + @get('id') + '/settings', 'get', forceAuth: true).then (data) ->
data['settings'] data['settings']
saveSettings: (settings) -> saveSettings: (settings) ->
Ajax.ajax('/repos/' + @get('id') + '/settings', 'patch', data: { settings: settings }) @get('ajax').ajax('/repos/' + @get('id') + '/settings', 'patch', data: { settings: settings })
Repo.reopenClass Repo.reopenClass
recent: -> recent: ->
@find() @find()
accessibleBy: (store, login) -> accessibleBy: (store, reposIds) ->
repos = store.find('repo', { member: login, orderBy: 'name' }) # this fires only for authenticated users and with API v3 that means getting
# only repos of currently logged in owner, but in the future it would be
# nice to not use that as it may change in the future
repos = store.filter('repo', (repo) ->
reposIds.indexOf(parseInt(repo.get('id'))) != -1
)
repos.then () -> promise = new Ember.RSVP.Promise (resolve, reject) ->
repos.set('isLoaded', true) store.query('repo', { 'repository.active': 'true' }).then( ->
resolve(repos)
, ->
reject()
)
repos promise
search: (store, query) -> search: (store, ajax, query) ->
promise = store.find('repo', search: query, orderBy: 'name') queryString = $.param(search: query, orderBy: 'name', limit: 5)
promise = ajax.ajax("/repos?#{queryString}", 'get')
result = Ember.ArrayProxy.create(content: []) result = Ember.ArrayProxy.create(content: [])
promise.then -> promise.then (data, status, xhr) ->
result.pushObjects(promise.get('content').toArray()) promises = data.repos.map (repoData) ->
result.set('isLoaded', true) store.findRecord('repo', repoData.id).then (record) ->
result.pushObject(record)
result.set('isLoaded', true)
record
result Ember.RSVP.allSettled(promises).then ->
result
withLastBuild: (store) -> withLastBuild: (store) ->
repos = store.filter('repo', {}, (build) -> repos = store.filter('repo', {}, (build) ->
build.get('lastBuildId') build.get('defaultBranch.lastBuild')
) )
repos.then () -> repos.then () ->
@ -176,20 +165,24 @@ Repo.reopenClass
repos repos
bySlug: (store, slug) ->
# first check if there is a repo with a given slug already ordered
repos = store.all('repo').filterBy('slug', slug)
if repos.get('length') > 0
repos
else
store.find('repo', { slug: slug })
fetchBySlug: (store, slug) -> fetchBySlug: (store, slug) ->
repos = @bySlug(store, slug) repos = store.peekAll('repo').filterBy('slug', slug)
if repos.get('length') > 0 if repos.get('length') > 0
repos.get('firstObject') repos.get('firstObject')
else else
repos.then (repos) -> adapter = store.adapterFor('repo')
modelClass = store.modelFor('repo')
adapter.findRecord(store, modelClass, slug).then (payload) ->
serializer = store.serializerFor('repo')
modelClass = store.modelFor('repo')
result = serializer.normalizeResponse(store, modelClass, payload, null, 'findRecord')
repo = store.push(data: result.data)
for record in result.included
r = store.push(data: record)
repo
, ->
error = new Error('repo not found') error = new Error('repo not found')
error.slug = slug error.slug = slug
Ember.get(repos, 'firstObject') || throw(error) Ember.get(repos, 'firstObject') || throw(error)

View File

@ -1,9 +1,13 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import Model from 'travis/models/model'` `import Model from 'travis/models/model'`
`import Ajax from 'travis/utils/ajax'`
`import config from 'travis/config/environment'` `import config from 'travis/config/environment'`
User = Model.extend User = Model.extend
ajax: Ember.inject.service()
# TODO: this totally not should be needed here
sessionStorage: Ember.inject.service()
name: DS.attr() name: DS.attr()
email: DS.attr() email: DS.attr()
login: DS.attr() login: DS.attr()
@ -27,7 +31,7 @@ User = Model.extend
).property() ).property()
_rawPermissions: (-> _rawPermissions: (->
Ajax.get('/users/permissions') @get('ajax').get('/users/permissions')
).property() ).property()
permissions: (-> permissions: (->
@ -72,12 +76,12 @@ User = Model.extend
sync: -> sync: ->
self = this self = this
Ajax.post('/users/sync', {}, -> @get('ajax').post('/users/sync', {}, ->
self.setWithSession('isSyncing', true) self.setWithSession('isSyncing', true)
) )
poll: -> poll: ->
Ajax.get '/users', (data) => @get('ajax').get '/users', (data) =>
if data.user.is_syncing if data.user.is_syncing
self = this self = this
setTimeout -> setTimeout ->
@ -88,12 +92,12 @@ User = Model.extend
@setWithSession('syncedAt', data.user.synced_at) @setWithSession('syncedAt', data.user.synced_at)
Travis.trigger('user:synced', data.user) Travis.trigger('user:synced', data.user)
@store.findQuery('account', {}) @store.query('account', {})
setWithSession: (name, value) -> setWithSession: (name, value) ->
@set(name, value) @set(name, value)
user = JSON.parse(Travis.sessionStorage.getItem('travis.user')) user = JSON.parse(@get('sessionStorage').getItem('travis.user'))
user[name.underscore()] = @get(name) user[name.underscore()] = @get(name)
Travis.sessionStorage.setItem('travis.user', JSON.stringify(user)) @get('sessionStorage').setItem('travis.user', JSON.stringify(user))
`export default User` `export default User`

View File

@ -13,7 +13,7 @@ Router = Ember.Router.extend
# #
# we should probably think about a more general way to # we should probably think about a more general way to
# do this, location should not know about auth status # do this, location should not know about auth status
Location.create(auth: @container.lookup('auth:main')) Location.create(auth: @container.lookup('service:auth'))
).property() ).property()
# TODO: this is needed, because in the original version # TODO: this is needed, because in the original version

View File

@ -2,7 +2,7 @@
Route = TravisRoute.extend Route = TravisRoute.extend
model: -> model: ->
@store.find('account', { all: true }) @store.query('account', { all: true })
setupController: (controller, model) -> setupController: (controller, model) ->
user = model.filterBy('type', 'user')[0] user = model.filterBy('type', 'user')[0]

View File

@ -21,7 +21,7 @@ Route = TravisRoute.extend BuildFaviconMixin,
@get('stylesheetsManager').disable('dashboard') @get('stylesheetsManager').disable('dashboard')
if !config.pro if !config.pro
repos = @get('store').all('repo') repos = @get('store').peekAll('repo')
repos.forEach (repo) => repos.forEach (repo) =>
@subscribeToRepo(repo) @subscribeToRepo(repo)

View File

@ -1,8 +1,9 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import TravisRoute from 'travis/routes/basic'` `import TravisRoute from 'travis/routes/basic'`
`import Ajax from 'travis/utils/ajax'`
Route = TravisRoute.extend Route = TravisRoute.extend
ajax: Ember.inject.service()
needsAuth: true needsAuth: true
setupController: (controller) -> setupController: (controller) ->
@_super.apply this, arguments @_super.apply this, arguments
@ -10,7 +11,7 @@ Route = TravisRoute.extend
model: -> model: ->
repo = @modelFor('repo') repo = @modelFor('repo')
Ajax.get("/repos/#{repo.get('id')}/caches").then( (data) -> @get('ajax').get("/repos/#{repo.get('id')}/caches").then( (data) ->
caches = {} caches = {}
data["caches"].forEach (cacheData) -> data["caches"].forEach (cacheData) ->

View File

@ -15,7 +15,7 @@ Route = SimpleLayoutRoute.extend
if !controller.get('isSyncing') if !controller.get('isSyncing')
self = this self = this
Ember.run.later this, -> Ember.run.later this, ->
@store.find('repo', member: @get('controller.user.login')).then( (repos) -> @store.query('repo', member: @get('controller.user.login')).then( (repos) ->
if repos.get('length') if repos.get('length')
self.transitionTo('main') self.transitionTo('main')
else else

View File

@ -1,5 +1,7 @@
`import TravisRoute from 'travis/routes/basic'` `import TravisRoute from 'travis/routes/basic'`
Route = TravisRoute.extend() Route = TravisRoute.extend
setupController: (controller)->
@container.lookup('controller:repos').activate('owned')
`export default Route` `export default Route`

View File

@ -21,10 +21,10 @@ Route = BasicRoute.extend
@_super.apply this, arguments @_super.apply this, arguments
loadMoreRepos: -> loadMoreRepos: ->
@store.find('build').then (builds) => @store.findAll('build').then (builds) =>
repoIds = builds.mapBy('data.repo').uniq() repoIds = builds.mapBy('data.repo').uniq()
repos = @get('repos.repos') repos = @get('repos.repos')
@store.find('repo', ids: repoIds).then (reposFromRequest) => @store.query('repo', ids: repoIds).then (reposFromRequest) =>
reposFromRequest.toArray().forEach (repo) -> reposFromRequest.toArray().forEach (repo) ->
repos.pushObject(repo) unless repos.contains(repo) repos.pushObject(repo) unless repos.contains(repo)

View File

@ -18,16 +18,18 @@ Route = TravisRoute.extend
@controllerFor('job').set('job', model) @controllerFor('job').set('job', model)
repo.activate('job') repo.activate('job')
if build = model.get('build') buildController = @controllerFor('build')
build = @store.recordForId('build', build.get('id'))
buildController = @controllerFor('build')
# this is a hack to not set favicon changes from build model.get('repo')
# controller while we're viewing job, this should go away if buildPromise = model.get('build')
# after refactoring of controllers buildPromise.then (build) =>
buildController.set('sendFaviconStateChanges', false) build = @store.recordForId('build', build.get('id'))
buildController.set('build', build)
buildController.set('build', build) # this is a hack to not set favicon changes from build
# controller while we're viewing job, this should go away
# after refactoring of controllers
buildController.set('sendFaviconStateChanges', false)
model: (params) -> model: (params) ->
@store.find('job', params.job_id) @store.find('job', params.job_id)

View File

@ -11,13 +11,11 @@ Route = TravisRoute.extend
@controllerFor('repo').activate('index') @controllerFor('repo').activate('index')
@controllerFor('repos').activate(@get('reposTabName')) @controllerFor('repos').activate(@get('reposTabName'))
@currentRepoDidChange() @setCurrentRepoObservers()
if repos = @controllerFor('repos').get('repos')
repos.addObserver('firstObject', this, 'currentRepoDidChange')
deactivate: -> deactivate: ->
if repos = @controllerFor('repos').get('repos') if repos = @controllerFor('repos')
repos.removeObserver('firstObject', this, 'currentRepoDidChange') repos.removeObserver('repos.firstObject', this, 'currentRepoDidChange')
@_super.apply(this, arguments) @_super.apply(this, arguments)
@ -25,6 +23,11 @@ Route = TravisRoute.extend
if repo = @controllerFor('repos').get('repos.firstObject') if repo = @controllerFor('repos').get('repos.firstObject')
@controllerFor('repo').set('repo', repo) @controllerFor('repo').set('repo', repo)
setCurrentRepoObservers: ->
@currentRepoDidChange()
if repos = @controllerFor('repos')
repos.addObserver('repos.firstObject', this, 'currentRepoDidChange')
actions: actions:
redirectToGettingStarted: -> redirectToGettingStarted: ->
@transitionTo('getting_started') @transitionTo('getting_started')

View File

@ -14,6 +14,6 @@ Route = TravisRoute.extend
setupController: (controller)-> setupController: (controller)->
# TODO: this is redundant with repositories and recent routes # TODO: this is redundant with repositories and recent routes
@container.lookup('controller:repos').activate('owned') #@container.lookup('controller:repos').activate('owned')
`export default Route` `export default Route`

View File

@ -10,8 +10,7 @@ Route = MainTabRoute.extend
@controllerFor('repo').activate('index') @controllerFor('repo').activate('index')
@controllerFor('repos').activate('search', searchPhrase) @controllerFor('repos').activate('search', searchPhrase)
@currentRepoDidChange() @setCurrentRepoObservers()
@controllerFor('repos').addObserver('firstObject', this, 'currentRepoDidChange')
model: (params) -> model: (params) ->
params.phrase.replace(/%2F/g, '/') params.phrase.replace(/%2F/g, '/')

View File

@ -1,6 +1,5 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import TravisRoute from 'travis/routes/basic'` `import TravisRoute from 'travis/routes/basic'`
`import Ajax from 'travis/utils/ajax'`
`import config from 'travis/config/environment'` `import config from 'travis/config/environment'`
Route = TravisRoute.extend Route = TravisRoute.extend

View File

@ -1,6 +1,5 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import TravisRoute from 'travis/routes/basic'` `import TravisRoute from 'travis/routes/basic'`
`import Ajax from 'travis/utils/ajax'`
`import config from 'travis/config/environment'` `import config from 'travis/config/environment'`
Route = TravisRoute.extend Route = TravisRoute.extend

View File

@ -1,6 +1,5 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import TravisRoute from 'travis/routes/basic'` `import TravisRoute from 'travis/routes/basic'`
`import Ajax from 'travis/utils/ajax'`
`import config from 'travis/config/environment'` `import config from 'travis/config/environment'`
Route = TravisRoute.extend Route = TravisRoute.extend

View File

@ -1,7 +1,9 @@
`import TravisRoute from 'travis/routes/basic'` `import TravisRoute from 'travis/routes/basic'`
`import Repo from 'travis/models/repo'` `import Repo from 'travis/models/repo'`
`import Ember from 'ember'`
Route = TravisRoute.extend Route = TravisRoute.extend
store: Ember.inject.service()
titleToken: (model) -> titleToken: (model) ->
model.get('slug') model.get('slug')
@ -9,9 +11,10 @@ Route = TravisRoute.extend
@render 'repo', into: 'main' @render 'repo', into: 'main'
setupController: (controller, model) -> setupController: (controller, model) ->
@container.lookup('controller:repos').activate('owned')
# TODO: if repo is just a data hash with id and slug load it # TODO: if repo is just a data hash with id and slug load it
# as incomplete record # as incomplete record
model = @store.find('repo', model.id) if model && !model.get model = @get('store').find('repo', model.id) if model && !model.get
controller.set('repo', model) controller.set('repo', model)
serialize: (repo) -> serialize: (repo) ->
@ -21,7 +24,7 @@ Route = TravisRoute.extend
model: (params) -> model: (params) ->
slug = "#{params.owner}/#{params.name}" slug = "#{params.owner}/#{params.name}"
Repo.fetchBySlug(@store, slug) Repo.fetchBySlug(@get('store'), slug)
resetController: -> resetController: ->
@controllerFor('repo').deactivate() @controllerFor('repo').deactivate()

View File

@ -6,7 +6,7 @@ Route = TravisRoute.extend
@controllerFor('repo').activate('current') @controllerFor('repo').activate('current')
renderTemplate: -> renderTemplate: ->
if @modelFor('repo').get('lastBuildId') if @modelFor('repo').get('defaultBranch.lastBuild')
@render 'build' @render 'build'
else else
@render 'builds/not_found' @render 'builds/not_found'

View File

@ -7,6 +7,6 @@ Route = TravisRoute.extend
@controllerFor('repo').activate('requests') @controllerFor('repo').activate('requests')
model: -> model: ->
@store.find 'request', repository_id: @modelFor('repo').get('id') @store.query 'request', repository_id: @modelFor('repo').get('id')
`export default Route` `export default Route`

View File

@ -1,8 +1,9 @@
`import TravisRoute from 'travis/routes/basic'` `import TravisRoute from 'travis/routes/basic'`
`import Ajax from 'travis/utils/ajax'`
`import config from 'travis/config/environment'` `import config from 'travis/config/environment'`
Route = TravisRoute.extend Route = TravisRoute.extend
ajax: Ember.inject.service()
needsAuth: true needsAuth: true
setupController: (controller, model) -> setupController: (controller, model) ->
@_super.apply(this, arguments) @_super.apply(this, arguments)
@ -27,7 +28,7 @@ Route = TravisRoute.extend
fetchSshKey: () -> fetchSshKey: () ->
repo = @modelFor('repo') repo = @modelFor('repo')
Ajax.get "/repos/#{repo.get('id')}/key", (data) => @get('ajax').get "/repos/#{repo.get('id')}/key", (data) =>
Ember.Object.create(fingerprint: data.fingerprint) Ember.Object.create(fingerprint: data.fingerprint)
fetchRepositoryActiveFlag: -> fetchRepositoryActiveFlag: ->

View File

@ -1,8 +1,9 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import Ajax from 'travis/utils/ajax'`
`import TravisRoute from 'travis/routes/basic'` `import TravisRoute from 'travis/routes/basic'`
Route = TravisRoute.extend Route = TravisRoute.extend
ajax: Ember.inject.service()
titleToken: 'Ssh Keys' titleToken: 'Ssh Keys'
model: (params) -> model: (params) ->
@ -17,7 +18,7 @@ Route = TravisRoute.extend
afterModel: (model, transition) -> afterModel: (model, transition) ->
repo = @modelFor('repo') repo = @modelFor('repo')
Ajax.get "/repos/#{repo.get('id')}/key", (data) => @get('ajax').get "/repos/#{repo.get('id')}/key", (data) =>
@defaultKey = Ember.Object.create(fingerprint: data.fingerprint) @defaultKey = Ember.Object.create(fingerprint: data.fingerprint)
setupController: (controller, model) -> setupController: (controller, model) ->

View File

@ -1,7 +1,7 @@
`import DS from 'ember-data'` `import DS from 'ember-data'`
`import V2FallbackSerializer from 'travis/serializers/v2_fallback'`
Serializer = DS.ActiveModelSerializer.extend Serializer = V2FallbackSerializer.extend
defaultSerializer: 'application' isNewSerializerAPI: true
serializer: 'application'
`export default Serializer` `export default Serializer`

12
app/serializers/branch.js Normal file
View File

@ -0,0 +1,12 @@
import Ember from 'ember';
import V2FallbackSerializer from 'travis/serializers/v2_fallback';
export default V2FallbackSerializer.extend({
extractAttributes(klass, payload) {
payload.id = payload['@href'];
return this._super(...arguments);
},
extractId(modelClass, resourceHash) {
return resourceHash.id || resourceHash['@href'];
}
});

View File

@ -1,19 +0,0 @@
`import Ember from 'ember'`
`import ApplicationSerializer from 'travis/serializers/application'`
Serializer = ApplicationSerializer.extend
attrs: {
repo: { key: 'repository_id' }
_config: { key: 'config' }
_finishedAt: { key: 'finished_at' }
_startedAt: { key: 'started_at' }
_duration: { key: 'duration' }
}
extractSingle: (store, primaryType, rawPayload, recordId) ->
if commit = rawPayload.commit
rawPayload.commits = [commit]
@_super(store, primaryType, rawPayload, recordId)
`export default Serializer`

109
app/serializers/build.js Normal file
View File

@ -0,0 +1,109 @@
import Ember from 'ember';
import V2FallbackSerializer from 'travis/serializers/v2_fallback';
var Serializer = V2FallbackSerializer.extend({
isNewSerializerAPI: true,
attrs: {
_config: {
key: 'config'
},
_finished_at: {
key: 'finished_at'
},
_started_at: {
key: 'started_at'
},
_duration: {
key: 'duration'
}
},
extractRelationships: function(modelClass, resourceHash) {
var result;
result = this._super(modelClass, resourceHash);
return result;
},
normalizeArrayResponse: function(store, primaryModelClass, payload, id, requestType) {
var result;
if (payload.commits) {
payload.builds.forEach(function(build) {
var commit, commit_id;
commit_id = build.commit_id;
if (commit = payload.commits.findBy('id', commit_id)) {
build.commit = commit;
return delete build.commit_id;
}
});
}
return this._super.apply(this, arguments);
},
keyForV2Relationship: function(key, typeClass, method) {
if(key === 'jobs') {
return 'job_ids';
} else if (key === 'repo') {
return 'repository_id';
} else if (key === 'commit') {
return key;
} else {
return this._super.apply(this, arguments);
}
},
keyForRelationship(key, typeClass, method) {
if (key === 'repo') {
return 'repository';
} else {
return this._super.apply(this, arguments);
}
},
normalize: function(modelClass, resourceHash) {
var data, href, id, repoId, result;
// TODO: remove this after switching to V3 entirely
if(!resourceHash['@type'] && resourceHash.commit && resourceHash.commit.branch_is_default) {
let build = resourceHash.build,
commit = resourceHash.commit;
let branch = {
name: commit.branch,
default_branch: commit.branch_is_default,
"@href": `/repo/${build.repository_id}/branch/${commit.branch}`
};
resourceHash.build.branch = branch;
}
// fix pusher payload, it doesn't include a branch record:
if(!resourceHash['@type'] && resourceHash.build &&
resourceHash.repository && resourceHash.repository.default_branch) {
let branchName = resourceHash.build.branch,
repository = resourceHash.repository,
defaultBranchName = repository.default_branch.name;
resourceHash.build.branch = {
name: branchName,
default_branch: branchName === defaultBranchName,
'@href': `/repo/${repository.id}/branch/${branchName}`
};
repository.default_branch['@href'] = `/repo/${repository.id}/branch/${defaultBranchName}`;
}
result = this._super(modelClass, resourceHash);
data = result.data;
if (repoId = resourceHash.repository_id) {
data.attributes.repositoryId = repoId;
} else if (resourceHash.repository) {
if (href = resourceHash.repository['@href']) {
id = href.match(/\d+/)[0];
data.attributes.repositoryId = id;
}
}
return result;
}
});
export default Serializer;

View File

@ -6,4 +6,7 @@ Serializer = ApplicationSerializer.extend
repo: { key: 'repository_id' } repo: { key: 'repository_id' }
} }
serialize: (snapshot, options) ->
return { env_var: this._super(snapshot, options) }
`export default Serializer` `export default Serializer`

7
app/serializers/hook.js Normal file
View File

@ -0,0 +1,7 @@
import ApplicationSerializer from 'travis/serializers/application';
export default ApplicationSerializer.extend({
serialize(snapshot, options) {
return { hook: this._super(...arguments) };
}
});

View File

@ -1,18 +1,30 @@
`import Ember from 'ember'` `import Ember from 'ember'`
`import ApplicationSerializer from 'travis/serializers/application'` `import V2FallbackSerializer from 'travis/serializers/v2_fallback'`
Serializer = ApplicationSerializer.extend Serializer = V2FallbackSerializer.extend
isNewSerializerAPI: true
attrs: { attrs: {
repo: { key: 'repository_id' }
_config: { key: 'config' } _config: { key: 'config' }
_finishedAt: { key: 'finished_at' } _finished_at: { key: 'finished_at' }
_startedAt: { key: 'started_at' } _started_at: { key: 'started_at' }
} }
extractSingle: (store, primaryType, rawPayload, recordId) -> keyForV2Relationship: (key, typeClass, method) ->
if commit = rawPayload.commit if key == 'repo'
rawPayload.commits = [commit] 'repository'
else
@_super.apply(this, arguments)
@_super(store, primaryType, rawPayload, recordId) keyForV2Relationship: (key, typeClass, method) ->
if key == 'repo'
'repository_id'
else
@_super.apply(this, arguments)
normalize: (modelClass, resourceHash) ->
if resourceHash.commit
resourceHash.commit['type'] = 'commit'
@_super(modelClass, resourceHash)
`export default Serializer` `export default Serializer`

View File

@ -1,9 +0,0 @@
`import Ember from 'ember'`
`import ApplicationSerializer from 'travis/serializers/application'`
Serializer = ApplicationSerializer.extend
attrs: {
_lastBuildDuration: { key: 'last_build_duration' }
}
`export default Serializer`

16
app/serializers/repo.js Normal file
View File

@ -0,0 +1,16 @@
import Ember from 'ember';
import V2FallbackSerializer from 'travis/serializers/v2_fallback';
var Serializer = V2FallbackSerializer.extend({
isNewSerializerAPI: true,
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
if(!id && requestType === 'findRecord') {
id = payload.id;
}
return this._super(store, primaryModelClass, payload, id, requestType);
}
});
export default Serializer;

View File

@ -1,11 +0,0 @@
`import Ember from 'ember'`
`import ApplicationSerializer from 'travis/serializers/application'`
Serializer = ApplicationSerializer.extend
attrs: {
branchName: { key: 'branch' }
tagName: { key: 'tag' }
repo: { key: 'repository_id' }
}
`export default Serializer`

View File

@ -0,0 +1,35 @@
import Ember from 'ember';
import V2FallbackSerializer from 'travis/serializers/v2_fallback';
var Serializer = V2FallbackSerializer.extend({
isNewSerializerAPI: true,
attrs: {
branch_name: { key: 'branch' },
tag_name: { key: 'tag' }
},
keyForV2Relationship: function(key, typeClass, method) {
if (key === 'repo') {
return 'repository_id';
} else {
return this._super.apply(this, arguments);
}
},
normalizeArrayResponse: function(store, primaryModelClass, payload, id, requestType) {
var result;
if (payload.commits) {
payload.requests.forEach(function(request) {
var commit, commit_id;
commit_id = request.commit_id;
if (commit = payload.commits.findBy('id', commit_id)) {
request.commit = commit;
return delete request.commit_id;
}
});
}
return this._super.apply(this, arguments);
}
});
export default Serializer;

View File

@ -0,0 +1,7 @@
import ApplicationSerializer from 'travis/serializers/application';
export default ApplicationSerializer.extend({
serialize(snapshot, options) {
return { ssh_key: this._super(...arguments) };
}
});

View File

@ -0,0 +1,94 @@
import Ember from 'ember';
import V3Serializer from 'travis/serializers/v3';
export default V3Serializer.extend({
isNewSerializerAPI: true,
extractRelationships(modelClass, resourceHash) {
if(resourceHash['@type']) {
return this._super(...arguments);
} else {
let relationships = {};
modelClass.eachRelationship((key, relationshipMeta) => {
// V2 API payload
let relationship = null;
let relationshipKey = this.keyForV2Relationship(key, relationshipMeta.kind, 'deserialize');
let alternativeRelationshipKey = key.underscore();
if (resourceHash.hasOwnProperty(alternativeRelationshipKey) || resourceHash.hasOwnProperty(relationshipKey)) {
let data = null;
let relationshipHash = resourceHash[alternativeRelationshipKey] || resourceHash[relationshipKey];
if (relationshipMeta.kind === 'belongsTo') {
data = this.extractRelationship(relationshipMeta.type, relationshipHash);
} else if (relationshipMeta.kind === 'hasMany') {
data = relationshipHash.map((item) => this.extractRelationship(relationshipMeta.type, item));
}
relationship = { data };
}
if (relationship) {
relationships[key] = relationship;
}
});
return relationships;
}
},
normalize(modelClass, resourceHash) {
if(resourceHash['@type']) {
return this._super(...arguments);
} else {
var modelKey = modelClass.modelName;
var attributes = resourceHash[modelKey];
if(attributes) {
for(var key in attributes) {
resourceHash[key] = attributes[key];
}
resourceHash['type'] = modelKey;
delete resourceHash[modelKey];
}
let { data, included } = this._super(...arguments);
if(!included) {
included = [];
}
let store = this.store;
if(data.relationships) {
Object.keys(data.relationships).forEach(function (key) {
let relationship = data.relationships[key];
let process = function(data) {
if(Object.keys(data).sort()+'' !== 'id,type' || (data['@href'] && data.type === 'branch')) {
// no need to add records if they have only id and type
let type = key === 'defaultBranch' ? 'branch' : key.singularize();
let serializer = store.serializerFor(type);
let modelClass = store.modelFor(type);
let normalized = serializer.normalize(modelClass, data);
included.push(normalized.data);
if(normalized.included) {
normalized.included.forEach(function(item) {
included.push(item);
});
}
}
};
if(Array.isArray(relationship.data)) {
relationship.data.forEach(process);
} else if(relationship && relationship.data) {
process(relationship.data);
}
});
}
return { data, included };
}
},
keyForV2Relationship(key, typeClass, method) {
return key.underscore() + '_id';
}
});

186
app/serializers/v3.js Normal file
View File

@ -0,0 +1,186 @@
import Ember from 'ember';
import DS from 'ember-data';
var traverse = function(object, callback) {
if(!object) {
return;
}
if(typeof(object) === 'object' && !Ember.isArray(object)) {
callback(object);
}
if(Ember.isArray(object)) {
for(let item of object) {
traverse(item, callback);
}
} else if(typeof object === 'object') {
for(let key in object) {
if(object.hasOwnProperty(key)) {
let item = object[key];
traverse(item, callback);
}
}
}
};
export default DS.JSONSerializer.extend({
isNewSerializerAPI: true,
extractRelationship(type, hash) {
if(hash && !hash.id && hash['@href']) {
hash.id = hash['@href'];
}
let relationshipHash = this._super(...arguments);
if(relationshipHash && relationshipHash['@type']) {
relationshipHash.type = relationshipHash['@type'];
} else if(relationshipHash && !relationshipHash.type) {
relationshipHash.type = type;
}
return relationshipHash;
},
extractRelationships() {
let relationships = this._super(...arguments);
return relationships;
},
keyForRelationship(key, typeClass, method) {
if(key && key.underscore) {
return key.underscore();
} else {
return key;
}
},
extractAttributes(modelClass, resourceHash) {
let attributes = this._super(...arguments);
for(let key in attributes) {
if(key.startsWith('@')) {
delete attributes.key;
}
}
return attributes;
},
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
this._fixReferences(payload);
return this._super(...arguments);
},
normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) {
let documentHash = {
data: null,
included: []
};
let meta = this.extractMeta(store, primaryModelClass, payload);
if (meta) {
Ember.assert('The `meta` returned from `extractMeta` has to be an object, not "' + Ember.typeOf(meta) + '".', Ember.typeOf(meta) === 'object');
documentHash.meta = meta;
}
let items, type;
if(type = payload['@type']) {
items = payload[type];
} else {
items = payload[primaryModelClass.modelName.underscore() + 's'];
}
documentHash.data = items.map((item) => {
let { data, included } = this.normalize(primaryModelClass, item);
if (included) {
documentHash.included.push(...included);
}
return data;
});
return documentHash;
},
normalize(modelClass, resourceHash) {
let { data, included } = this._super(...arguments);
if(!included) {
included = [];
}
let store = this.store;
if(data.relationships) {
Object.keys(data.relationships).forEach(function (key) {
let relationship = data.relationships[key];
let process = function(data) {
if(data['@representation'] !== 'standard') {
return;
}
let type = data['@type'];
let serializer = store.serializerFor(type);
let modelClass = store.modelFor(type);
let normalized = serializer.normalize(modelClass, data);
included.push(normalized.data);
if(normalized.included) {
normalized.included.forEach(function(item) {
included.push(item);
});
}
};
if(Array.isArray(relationship.data)) {
relationship.data.forEach(process);
} else if(relationship && relationship.data) {
process(relationship.data);
}
});
}
return { data, included };
},
keyForAttribute(key, method) {
if(method === 'deserialize') {
return Ember.String.underscore(key);
} else {
return Ember.String.camelize(key);
}
},
_fixReferences(payload) {
let byHref = {}, href, records;
if(payload['@type']) {
// API V3 doesn't return all of the objects in a full representation
// If an object is present in one place in the response, all of the
// other occurences will be just references of a kind - they will just
// include @href property.
//
// I don't want to identify records by href in ember-data, so here I'll
// set an id and a @type field on all of the references.
//
// First we need to group all of the items in the response by href:
traverse(payload, (item) => {
if(href = item['@href']) {
if(records = byHref[href]) {
records.push(item);
} else {
byHref[href] = [item];
}
}
});
// Then we can choose a record with an id for each href and put the id
// in all of the other occurences.
for(let href in byHref) {
records = byHref[href];
let recordWithAnId = records.find( (record) => record.id );
if(recordWithAnId) {
for(let record of records) {
record.id = recordWithAnId.id;
//record['@type'] = recordWithAnId['@type'];
}
}
}
}
return payload;
}
});

View File

@ -7,7 +7,9 @@ default_options =
accepts: accepts:
json: 'application/json; version=2' json: 'application/json; version=2'
ajax = Em.Object.create Ajax = Ember.Service.extend
auth: Ember.inject.service()
publicEndpoints: [/\/repos\/?.*/, /\/builds\/?.*/, /\/jobs\/?.*/] publicEndpoints: [/\/repos\/?.*/, /\/builds\/?.*/, /\/jobs\/?.*/]
privateEndpoints: [/\/repos\/\d+\/caches/] privateEndpoints: [/\/repos\/\d+\/caches/]
@ -42,8 +44,8 @@ ajax = Em.Object.create
endpoint = config.apiEndpoint || '' endpoint = config.apiEndpoint || ''
options = options || {} options = options || {}
token = Travis.sessionStorage.getItem('travis.token') token = Ember.get(this, 'auth').token()
if token && (ajax.needsAuth(method, url) || options.forceAuth) if token && (@needsAuth(method, url) || options.forceAuth)
options.headers ||= {} options.headers ||= {}
options.headers['Authorization'] ||= "token #{token}" options.headers['Authorization'] ||= "token #{token}"
@ -66,9 +68,9 @@ ajax = Em.Object.create
error = options.error || (->) error = options.error || (->)
options.error = (data, status, xhr) => options.error = (data, status, xhr) =>
console.log "[ERROR] API responded with an error (#{status}): #{JSON.stringify(data)}"
Travis.lookup('controller:flash').pushObject(data.flash) if data?.flash Travis.lookup('controller:flash').pushObject(data.flash) if data?.flash
delete data.flash if data? delete data.flash if data?
console.log "[ERROR] API responded with an error (#{status}): #{JSON.stringify(data)}"
error.apply(this, arguments) error.apply(this, arguments)
options = $.extend(options, default_options) options = $.extend(options, default_options)
@ -153,4 +155,4 @@ ajax = Em.Object.create
return promise return promise
`export default ajax` `export default Ajax`

View File

@ -1,7 +1,11 @@
`import config from 'travis/config/environment'` `import config from 'travis/config/environment'`
`import Ajax from 'travis/utils/ajax'`
Auth = Ember.Object.extend Auth = Ember.Service.extend
store: Ember.inject.service(),
storage: Ember.inject.service(),
sessionStorage: Ember.inject.service(),
ajax: Ember.inject.service()
state: "signed-out" state: "signed-out"
receivingEnd: "#{location.protocol}//#{location.host}" receivingEnd: "#{location.protocol}//#{location.host}"
@ -9,20 +13,20 @@ Auth = Ember.Object.extend
window.addEventListener('message', (e) => @receiveMessage(e)) window.addEventListener('message', (e) => @receiveMessage(e))
token: -> token: ->
Travis.sessionStorage.getItem('travis.token') @get('sessionStorage').getItem('travis.token')
endpoint: (-> endpoint: (->
config.apiEndpoint config.apiEndpoint
).property(), ).property(),
signOut: -> signOut: ->
@storage.removeItem('travis.user') @get('storage').removeItem('travis.user')
@storage.removeItem('travis.token') @get('storage').removeItem('travis.token')
@sessionStorage.clear() @get('sessionStorage').clear()
@set('state', 'signed-out') @set('state', 'signed-out')
@set('user', undefined) @set('user', undefined)
if user = @get('currentUser') if user = @get('currentUser')
@store.unloadAll('user') @get('store').unloadAll('user')
@set('currentUser', null) @set('currentUser', null)
@sendToApp('afterSignOut') @sendToApp('afterSignOut')
Travis.trigger('user:signed_out') Travis.trigger('user:signed_out')
@ -36,7 +40,7 @@ Auth = Ember.Object.extend
$('<iframe id="auth-frame" />').hide().appendTo('body').attr('src', url) $('<iframe id="auth-frame" />').hide().appendTo('body').attr('src', url)
autoSignIn: (data) -> autoSignIn: (data) ->
data ||= @userDataFrom(@sessionStorage) || @userDataFrom(@storage) data ||= @userDataFrom(@get('sessionStorage')) || @userDataFrom(@get('storage'))
@setData(data) if data @setData(data) if data
userDataFrom: (storage) -> userDataFrom: (storage) ->
@ -54,7 +58,7 @@ Auth = Ember.Object.extend
validateUser: (user) -> validateUser: (user) ->
fieldsToValidate = ['id', 'login', 'token'] fieldsToValidate = ['id', 'login', 'token']
isTravisBecome = sessionStorage.getItem('travis.become') isTravisBecome = @get('sessionStorage').getItem('travis.become')
unless isTravisBecome unless isTravisBecome
fieldsToValidate.push 'correct_scopes' fieldsToValidate.push 'correct_scopes'
@ -72,8 +76,8 @@ Auth = Ember.Object.extend
false false
setData: (data) -> setData: (data) ->
@storeData(data, @sessionStorage) @storeData(data, @get('sessionStorage'))
@storeData(data, @storage) unless @userDataFrom(@storage) @storeData(data, @get('storage')) unless @userDataFrom(@get('storage'))
user = @loadUser(data.user) user = @loadUser(data.user)
@set('currentUser', user) @set('currentUser', user)
@ -83,19 +87,19 @@ Auth = Ember.Object.extend
refreshUserData: (user) -> refreshUserData: (user) ->
unless user unless user
if data = @userDataFrom(@sessionStorage) || @userDataFrom(@storage) if data = @userDataFrom(@get('sessionStorage')) || @userDataFrom(@get('storage'))
user = data.user user = data.user
if user if user
Ajax.get("/users/#{user.id}").then (data) => @get('ajax').get("/users/#{user.id}").then (data) =>
if data.user.correct_scopes if data.user.correct_scopes
userRecord = @loadUser(data.user) userRecord = @loadUser(data.user)
userRecord.get('permissions') userRecord.get('permissions')
# if user is still signed in, update saved data # if user is still signed in, update saved data
if @get('signedIn') if @get('signedIn')
data.user.token = user.token data.user.token = user.token
@storeData(data, @sessionStorage) @storeData(data, @get('sessionStorage'))
@storeData(data, @storage) @storeData(data, @get('storage'))
Travis.trigger('user:refreshed', data.user) Travis.trigger('user:refreshed', data.user)
else else
return Ember.RSVP.Promise.reject() return Ember.RSVP.Promise.reject()
@ -119,8 +123,13 @@ Auth = Ember.Object.extend
storage.setItem('travis.user', JSON.stringify(data.user)) storage.setItem('travis.user', JSON.stringify(data.user))
loadUser: (user) -> loadUser: (user) ->
@store.pushPayload(users: [user]) @get('store').push(
@store.recordForId('user', user.id) data:
type: 'user',
id: user.id
attributes: user
)
@get('store').recordForId('user', user.id)
receiveMessage: (event) -> receiveMessage: (event) ->
if event.origin == @expectedOrigin() if event.origin == @expectedOrigin()

View File

@ -0,0 +1,18 @@
`import Ember from 'ember'`
`import StorageService from 'travis/services/storage'`
`import Storage from 'travis/utils/hash-storage'`
SessionStorageService = StorageService.extend
init: ->
storage = null
try
# firefox will not throw error on access for sessionStorage var,
# you need to actually get something from session
window.sessionStorage.getItem('foo')
storage = window.sessionStorage
catch err
storage = Storage.create()
@set('storage', storage)
`export default SessionStorageService`

View File

@ -0,0 +1,22 @@
`import Ember from 'ember'`
`import Storage from 'travis/utils/hash-storage'`
StorageService = Ember.Service.extend
init: ->
storage = null
try
storage = window.localStorage || throw('no storage')
catch err
storage = Storage.create()
@set('storage', storage)
getItem: (key) ->
return @get("storage").getItem(key)
setItem: (key, value) ->
return @get("storage").setItem(key, value)
removeItem: (key) ->
return @get("storage").removeItem(key)
clear: ->
return @get("storage").clear()
`export default StorageService`

View File

@ -2,6 +2,8 @@
`import config from 'travis/config/environment'` `import config from 'travis/config/environment'`
Store = DS.Store.extend Store = DS.Store.extend
auth: Ember.inject.service()
defaultAdapter: 'application' defaultAdapter: 'application'
adapter: 'application' adapter: 'application'
@ -17,21 +19,6 @@ Store = DS.Store.extend
canHandleEvent: (event, data) -> canHandleEvent: (event, data) ->
[name, type] = event.split(':') [name, type] = event.split(':')
auth = @container.lookup('auth:main')
if event != 'job:log' && auth.get('signedIn') &&
!config.pro && !config.enterprise
# if recent repos hasn't been opened yet, we can safely
# drop any events that doesn't belong to repos owned by
# the logged in user and that aren't related to any
# repositories that are already opened
permissions = auth.get('permissions')
if name == 'job'
id = data.job.repository_id
else if name == 'build'
id = data.repository.id
return @hasRecordForId('repo', id) || permissions.contains(id)
for name, callback of @get('pusherEventHandlerGuards') for name, callback of @get('pusherEventHandlerGuards')
unless callback(event, data) unless callback(event, data)
@ -45,7 +32,7 @@ Store = DS.Store.extend
return unless @canHandleEvent(event, data) return unless @canHandleEvent(event, data)
if name == 'job' && data.job?.commit if name == 'job' && data.job?.commit
@pushPayload(commits: [data.job.commit]) @push(this.normalize('commit', data.job.commit))
if name == 'build' && data.build?.commit if name == 'build' && data.build?.commit
# TODO: commit should be a sideload record on build, not mixed with it # TODO: commit should be a sideload record on build, not mixed with it
@ -64,27 +51,41 @@ Store = DS.Store.extend
} }
delete(data.build.commit) delete(data.build.commit)
@pushPayload(commits: [commit]) @push(this.normalize('commit', commit))
if event == 'job:log' if event == 'job:log'
data = data.job data = data.job
job = @recordForId('job', data.id) job = @recordForId('job', data.id)
job.appendLog(number: parseInt(data.number), content: data._log, final: data.final) job.appendLog(number: parseInt(data.number), content: data._log, final: data.final)
else if data[name] else if data[name]
@_loadOne(name, data) @loadOne(name, data)
else else
throw "can't load data for #{name}" unless type throw "can't load data for #{name}" unless type
_loadOne: (type, json) -> loadOne: (type, json) ->
payload = {} record = @push(this.normalize(type, json))
payload[type.pluralize()] = [json[type]]
@pushPayload(payload)
# we get other types of records only in a few situations and # we get other types of records only in a few situations and
# it's not always needed to update data, so I'm specyfing which # it's not always needed to update data, so I'm specyfing which
# things I want to update here: # things I want to update here:
if type == 'build' && (json.repository || json.repo) if type == 'build' && (json.repository || json.repo)
data = json.repository || json.repo data = json.repository || json.repo
@pushPayload(repos: [data])
default_branch = data.default_branch
if default_branch
default_branch.default_branch = true
last_build_id = default_branch.last_build_id
# a build is a synchronous relationship on a branch model, so we need to
# have a build record present when we put default_branch from a repository
# model into the store. We don't send last_build's payload in pusher, so
# we need to get it here, if it's not already in the store. In the future
# we may decide to make this relationship async, but I don't want to
# change the code at the moment
if build = @peekRecord('build', last_build_id)
@push(this.normalize('repo', data))
else
@findRecord('build', last_build_id).then =>
@push(this.normalize('repo', data))
`export default Store` `export default Store`

View File

@ -5,7 +5,7 @@
<small class="commit-branch" title={{item.pullRequestTitle}}>Pull Request #{{item.pullRequestNumber}}</small> <small class="commit-branch" title={{item.pullRequestTitle}}>Pull Request #{{item.pullRequestNumber}}</small>
{{item.pullRequestTitle}} {{item.pullRequestTitle}}
{{else}} {{else}}
<small class="commit-branch" title={{item.commit.branch}}>{{item.commit.branch}}</small> <small class="commit-branch" title={{item.branch.name}}>{{item.branch.name}}</small>
{{format-message item.commit.subject repo=item.repo}} {{format-message item.commit.subject repo=item.repo}}
{{/if}} {{/if}}
</h2> </h2>

View File

@ -1,5 +1,5 @@
<div id="code-climate" class="popup"> <div id="code-climate" class="popup">
<img src="/images/icons/code-climate-logo.svg" id="code-climate-logo"/> <img src="/images/ui/code-climate-logo.svg" id="code-climate-logo"/>
<a href="#" class="close" {{action "close"}}></a> <a href="#" class="close" {{action "close"}}></a>
<p> <p>
<b>Want test coverage for your tests?</b> <b>Want test coverage for your tests?</b>

View File

@ -1,38 +1,37 @@
<div class="tile {{repo.lastBuildState}}"> <div class="tile {{repo.defaultBranch.lastBuild.state}}">
<h2 class="tile-title {{repo.lastBuildState}}"> <h2 class="tile-title {{repo.defaultBranch.lastBuild.state}}">
{{#if repo.slug}} {{#if repo.slug}}
{{#link-to "repo" repo}} {{#link-to "repo" repo}}
{{status-icon status=repo.lastBuildState}} {{status-icon status=repo.defaultBranch.lastBuild.state}}
<span class="label-align">{{repo.slug}}</span> <span class="label-align">{{repo.slug}}</span>
{{/link-to}} {{/link-to}}
{{/if}} {{/if}}
</h2> </h2>
{{#with repo.lastBuildHash as lastBuild}}
{{#if repo.slug}} {{#if repo.slug}}
{{#if lastBuild.id}} {{#if repo.defaultBranch.lastBuild.id}}
<p class="tile-title float-right {{repo.lastBuildState}}"> <p class="tile-title float-right {{repo.defaultBranch.lastBuild.state}}">
{{#link-to "build" repo lastBuild.id}} {{#link-to "build" repo repo.defaultBranch.lastBuild.id}}
<span class="icon-hash"></span> <span class="icon-hash"></span>
<span class="label-align">{{lastBuild.number}}</span> <span class="label-align">{{repo.defaultBranch.lastBuild.number}}</span>
{{/link-to}} {{/link-to}}
</p> </p>
{{/if}}
{{/if}} {{/if}}
{{/with}} {{/if}}
<p> <p>
<span class="icon-clock"></span> <span class="icon-clock"></span>
<span class="label-align">Duration: <span class="label-align">Duration:
<abbr class="duration" title={{lastBuildStartedAt}}> <abbr class="duration" title={{repo.defaultBranch.lastBuild.startedAt}}>
{{format-duration repo.lastBuildDuration}} {{format-duration repo.defaultBranch.lastBuild.duration}}
</abbr></span> </abbr></span>
</p> </p>
<p> <p>
<span class="icon-calendar"></span> <span class="icon-calendar"></span>
<span class="label-align">Finished: <span class="label-align">Finished:
<abbr class="finished_at timeago" title={{lastBuildFinishedAt}}> <abbr class="finished_at timeago" title={{repo.defaultBranch.lastBuild.finishedAt}}>
{{format-time repo.lastBuildFinishedAt}} {{format-time repo.defaultBranch.lastBuild.finishedAt}}
</abbr></span> </abbr></span>
</p> </p>
</div> </div>

View File

@ -3,5 +3,3 @@
{{else}} {{else}}
<p class="empty">{{noReposMessage}}</p> <p class="empty">{{noReposMessage}}</p>
{{/each}} {{/each}}

View File

@ -26,7 +26,7 @@
{{#if repo.active}} {{#if repo.active}}
{{outlet}} {{outlet}}
{{else}} {{else}}
{{#if repo.lastBuildId}} {{#if repo.defaultBranch.lastBuild.id}}
{{outlet}} {{outlet}}
{{else}} {{else}}
{{not-active user=currentUser repo=repo}} {{not-active user=currentUser repo=repo}}

Some files were not shown because too many files have changed in this diff Show More