diff --git a/.travis.yml b/.travis.yml index d4bdd2a7..c407e03b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,19 @@ language: ruby rvm: - 2.1.2 - + sudo: false cache: bundler: true +matrix: + allow_failures: + - rvm: 2.1.2 + env: 'TEST_SUITE=phantomjs' + - rvm: 2.1.2 + env: "TEST_SUITE=saucelabs BROWSER='firefox::Windows XP'" + env: global: - secure: "RFuCOppyjWHC4XWKtQlgS4zO4B6KVxytdX8+G5jRY3XM+OEGte8VDD88gZLM\nKDpkqMFDbNJAVTsh1kMANCTct2ONi30RTxuJWLtRyK7RE5zCcaGbAkTNZgXo\nOR5OWLEPJZbNfbh17H6J7izTy6yiLR+CsVP1wMgeVusP0eoDhCA=" diff --git a/assets/images/ui/activated.png b/assets/images/ui/activated.png new file mode 100644 index 00000000..450c6099 Binary files /dev/null and b/assets/images/ui/activated.png differ diff --git a/assets/images/ui/charmtab.png b/assets/images/ui/charmtab.png new file mode 100644 index 00000000..f30e92fb Binary files /dev/null and b/assets/images/ui/charmtab.png differ diff --git a/assets/images/ui/slider-closed.png b/assets/images/ui/slider-closed.png new file mode 100644 index 00000000..4f2ca670 Binary files /dev/null and b/assets/images/ui/slider-closed.png differ diff --git a/assets/images/ui/slider-open.png b/assets/images/ui/slider-open.png new file mode 100644 index 00000000..6a037b7b Binary files /dev/null and b/assets/images/ui/slider-open.png differ diff --git a/assets/scripts/app/app.coffee b/assets/scripts/app/app.coffee index d79fbb61..4fbe783c 100644 --- a/assets/scripts/app/app.coffee +++ b/assets/scripts/app/app.coffee @@ -145,3 +145,45 @@ unless window.TravisApplication currentDate: -> new Date() ) + + onUserUpdate: (user) -> + if Travis.config.pro + @identifyCustomer(user) + @subscribePusher(user) + @setupCharm(user) + + subscribePusher: (user) -> + channels = user.channels + channels = channels.map (channel) -> + if channel.match /^private-/ + channel + else + "private-#{channel}" + Travis.pusher.subscribeAll(channels) + + setupCharm: (user) -> + $.extend window.__CHARM, + customer: user.login, + customer_id: user.id, + email: user.email + + displayCharm: -> + __CHARM.show() + + identifyCustomer: (user) -> + if _cio && _cio.identify + _cio.identify + id: user.id + email: user.email + name: user.name + created_at: (Date.parse(user.created_at) / 1000) || null + login: user.login + + @on 'user:signed_in', (user) -> + Travis.onUserUpdate(user) + + @on 'user:synced', (user) -> + Travis.onUserUpdate(user) + + @_super.apply this, arguments + diff --git a/assets/scripts/app/auth.coffee b/assets/scripts/app/auth.coffee index 613c44d7..ba6f6cef 100644 --- a/assets/scripts/app/auth.coffee +++ b/assets/scripts/app/auth.coffee @@ -46,7 +46,11 @@ window.Auth = Ember.Object.extend null validateUser: (user) -> - @validateHas('id', user) && @validateHas('login', user) && @validateHas('token', user) && @validateHas('correct_scopes', user) && user.correct_scopes + fieldsToValidate = ['id', 'login', 'token', 'correct_scopes'] + if Travis.config.pro + fieldsToValidate.push 'channels' + + fieldsToValidate.every( (field) => @validateHas(field, user) ) && user.correct_scopes validateHas: (field, user) -> if user[field] diff --git a/assets/scripts/app/controllers.coffee b/assets/scripts/app/controllers.coffee index a8c9be07..c9653c51 100644 --- a/assets/scripts/app/controllers.coffee +++ b/assets/scripts/app/controllers.coffee @@ -25,20 +25,12 @@ Travis.TopController = Em.Controller.extend Travis.get('authState') == 'signing-in' ).property('Travis.authState') -Travis.ApplicationController = Em.Controller.extend - templateName: 'layouts/home' - - connectLayout: (name) -> - name = "layouts/#{name}" - if @get('templateName') != name - @set('templateName', name) - Travis.MainController = Em.Controller.extend() Travis.StatsLayoutController = Em.Controller.extend() Travis.ProfileLayoutController = Em.Controller.extend() Travis.AuthLayoutController = Em.Controller.extend() -Travis.ProfileInfoController = Em.Controller.extend +Travis.AccountsInfoController = Em.Controller.extend needs: ['currentUser', 'repos'] userBinding: 'controllers.currentUser' @@ -49,6 +41,33 @@ Travis.FirstSyncController = Em.Controller.extend isSyncing: Ember.computed.alias('user.isSyncing') Travis.IndexErrorController = Em.Controller.extend() +Travis.BuildsItemController = Em.ObjectController.extend(Travis.GithubUrlProperties) + +Travis.QueuesController = Em.ArrayController.extend + content: (-> + Travis.Job.queued() + ).property() + +Travis.RunningJobsController = Em.ArrayController.extend + content: (-> + Travis.Job.running() + ).property() + +Travis.SidebarController = Em.ArrayController.extend + init: -> + @_super.apply this, arguments + @tickables = [] + + tips: [ + "Did you know that you can parallelize tests on Travis CI? Learn more" + "Did you know that you can split a build into several smaller pieces? Learn more" + "Did you know that you can skip a build? Learn more" + ] + + tip: (-> + if tips = @get('tips') + tips[Math.floor(Math.random()*tips.length)] + ).property().volatile() require 'controllers/accounts' require 'controllers/auth' diff --git a/assets/scripts/app/controllers/account.coffee b/assets/scripts/app/controllers/account.coffee index 36fe2bae..182a2ab6 100644 --- a/assets/scripts/app/controllers/account.coffee +++ b/assets/scripts/app/controllers/account.coffee @@ -11,8 +11,12 @@ Travis.AccountController = Ember.ObjectController.extend self.reloadHooks() )) - toggle: (hook) -> - hook.toggle() + actions: + sync: -> + @get('user').sync() + + toggle: (hook) -> + hook.toggle() reloadHooks: -> if login = @get('login') @@ -35,8 +39,3 @@ Travis.AccountController = Ember.ObjectController.extend showPublicReposHint: (-> Travis.config.show_repos_hint == 'public' ) .property() - - actions: - sync: -> - @get('user').sync() - diff --git a/assets/scripts/app/controllers/build.coffee b/assets/scripts/app/controllers/build.coffee index 6e61ab6f..c8763418 100644 --- a/assets/scripts/app/controllers/build.coffee +++ b/assets/scripts/app/controllers/build.coffee @@ -1,4 +1,4 @@ -Travis.BuildController = Ember.Controller.extend +Travis.BuildController = Ember.Controller.extend Travis.GithubUrlProperties, needs: ['repo'] repoBinding: 'controllers.repo.repo' commitBinding: 'build.commit' @@ -10,7 +10,3 @@ Travis.BuildController = Ember.Controller.extend loading: (-> @get('build.isLoading') ).property('build.isLoading') - - urlGithubCommit: (-> - Travis.Urls.githubCommit(@get('repo.slug'), @get('commit.sha')) - ).property('repo.slug', 'commit.sha') diff --git a/assets/scripts/app/controllers/builds.coffee b/assets/scripts/app/controllers/builds.coffee index 7339c3f5..1ebd215e 100644 --- a/assets/scripts/app/controllers/builds.coffee +++ b/assets/scripts/app/controllers/builds.coffee @@ -1,4 +1,6 @@ Travis.BuildsController = Em.ArrayController.extend + isPullRequestsList: false + sortAscending: false sortProperties: ['number'] diff --git a/assets/scripts/app/controllers/current_user.coffee b/assets/scripts/app/controllers/current_user.coffee index affccf9c..4b8ca9e4 100644 --- a/assets/scripts/app/controllers/current_user.coffee +++ b/assets/scripts/app/controllers/current_user.coffee @@ -1,19 +1,11 @@ -delegate = (name, options) -> - options ||= options - -> - target = @get(options.to) - target[name].apply(target, arguments) - Travis.CurrentUserController = Em.ObjectController.extend sync: -> - @get('content').sync() + @get('model').sync() - content: (-> - @get('auth.currentUser') - ).property('auth.currentUser') + model: Ember.computed.alias('auth.currentUser') syncingDidChange: (-> - if (user = @get('content')) && user.get('isSyncing') && !user.get('syncedAt') + if (user = @get('model')) && user.get('isSyncing') && !user.get('syncedAt') Ember.run.scheduleOnce 'routerTransitions', this, -> @container.lookup('router:main').send('renderFirstSync') - ).observes('isSyncing', 'content') + ).observes('isSyncing', 'auth.currentUser') diff --git a/assets/scripts/app/controllers/flash.coffee b/assets/scripts/app/controllers/flash.coffee index 721b629f..8a10eaae 100644 --- a/assets/scripts/app/controllers/flash.coffee +++ b/assets/scripts/app/controllers/flash.coffee @@ -6,13 +6,13 @@ Travis.FlashController = Ember.ArrayController.extend @_super.apply this, arguments @set('flashes', Travis.LimitedArray.create(limit: 2, content: [])) - content: (-> + model: (-> broadcasts = @get('unseenBroadcasts') flashes = @get('flashes') - content = [] - content = content.concat(broadcasts.toArray()) if broadcasts - content = content.concat(flashes.toArray().reverse()) if flashes - content.uniq() + model = [] + model = model.concat(broadcasts.toArray()) if broadcasts + model = model.concat(flashes.toArray().reverse()) if flashes + model.uniq() ).property('unseenBroadcasts.length', 'flashes.length') unseenBroadcasts: (-> @@ -30,10 +30,11 @@ Travis.FlashController = Ember.ArrayController.extend @get('flashes').unshiftObject(msg) Ember.run.later(this, (-> @get('flashes.content').removeObject(msg)), 15000) - close: (msg) -> - if msg instanceof Travis.Broadcast - msg.setSeen() - @notifyPropertyChange('unseenBroadcasts') - else - @get('flashes').removeObject(msg) + actions: + close: (msg) -> + if msg instanceof Travis.Broadcast + msg.setSeen() + @notifyPropertyChange('unseenBroadcasts') + else + @get('flashes').removeObject(msg) diff --git a/assets/scripts/app/controllers/job.coffee b/assets/scripts/app/controllers/job.coffee index 193aab42..5705e0d6 100644 --- a/assets/scripts/app/controllers/job.coffee +++ b/assets/scripts/app/controllers/job.coffee @@ -1,7 +1,6 @@ Travis.JobController = Em.Controller.extend needs: ['repo'] - jobBinding: 'controllers.repo.job' repoBinding: 'controllers.repo.repo' commitBinding: 'job.commit' annotationsBinding: 'job.annotations' diff --git a/assets/scripts/app/controllers/profile.coffee b/assets/scripts/app/controllers/profile.coffee index a2498206..298f3700 100644 --- a/assets/scripts/app/controllers/profile.coffee +++ b/assets/scripts/app/controllers/profile.coffee @@ -16,5 +16,14 @@ Travis.ProfileController = Travis.Controller.extend @connectTab('user') connectTab: (tab) -> - viewClass = Travis["#{$.camelize(tab)}View"] + if tab == 'user' + view = 'AccountsInfoView' + else + view = "#{$.camelize(tab)}View" + viewClass = Travis[view] @set('tab', tab) + + billingUrl: (-> + id = if @get('account.type') == 'user' then 'user' else @get('account.login') + "#{Travis.config.billing_endpoint}/subscriptions/#{id}" + ).property('account.login', 'account.type') diff --git a/assets/scripts/app/controllers/repo.coffee b/assets/scripts/app/controllers/repo.coffee index 4144b681..a2d73bf5 100644 --- a/assets/scripts/app/controllers/repo.coffee +++ b/assets/scripts/app/controllers/repo.coffee @@ -1,8 +1,9 @@ Travis.RepoController = Travis.Controller.extend - needs: ['repos', 'currentUser', 'build', 'request'] + needs: ['repos', 'currentUser', 'build', 'request', 'job'] currentUserBinding: 'controllers.currentUser' build: Ember.computed.alias('controllers.build.build') + job: Ember.computed.alias('controllers.job.job') request: Ember.computed.alias('controllers.request.model') slug: (-> @get('repo.slug') ).property('repo.slug') @@ -10,7 +11,8 @@ Travis.RepoController = Travis.Controller.extend init: -> @_super.apply this, arguments - Visibility.every Travis.INTERVALS.updateTimes, @updateTimes.bind(this) + if !Ember.testing + Visibility.every Travis.INTERVALS.updateTimes, @updateTimes.bind(this) updateTimes: -> Ember.run this, -> @@ -23,6 +25,9 @@ Travis.RepoController = Travis.Controller.extend if build && jobs = build.get('jobs') jobs.forEach (j) -> j.updateTimes() + deactivate: -> + @stopObservingLastBuild() + activate: (action) -> @stopObservingLastBuild() this["view#{$.camelize(action)}"]() diff --git a/assets/scripts/app/controllers/repos.coffee b/assets/scripts/app/controllers/repos.coffee index 8bb5a377..7df3d16b 100644 --- a/assets/scripts/app/controllers/repos.coffee +++ b/assets/scripts/app/controllers/repos.coffee @@ -1,19 +1,9 @@ require 'travis/limited_array' Travis.ReposController = Ember.ArrayController.extend - defaultTab: ( -> - if @get('currentUser.id') - 'owned' - else - 'recent' - ).property('currentUser.id') - - currentUserIdDidChange: (-> - if @get('currentUser.id') - @activate('owned') - else if @get('tab') == 'owned' - @activate('recent') - ).observes('currentUser.id') + actions: + activate: (name) -> + @activate(name) tabOrIsLoadedDidChange: (-> @possiblyRedirectToGettingStartedPage() @@ -36,7 +26,8 @@ Travis.ReposController = Ember.ArrayController.extend init: -> @_super.apply this, arguments - Visibility.every Travis.INTERVALS.updateTimes, @updateTimes.bind(this) + if !Ember.testing + Visibility.every Travis.INTERVALS.updateTimes, @updateTimes.bind(this) recentRepos: (-> Ember.ArrayProxy.extend( @@ -53,13 +44,8 @@ Travis.ReposController = Ember.ArrayController.extend if content = @get('content') content.forEach (r) -> r.updateTimes() - transitionToRoot: -> - @container.lookup('router:main').send('renderDefaultTemplate') - @container.lookup('router:main').transitionTo('index.current') - activate: (tab, params) -> @set('sortProperties', ['sortOrder']) - tab ||= @get('defaultTab') @set('tab', tab) this["view#{$.camelize(tab)}"](params) @@ -76,22 +62,20 @@ Travis.ReposController = Ember.ArrayController.extend [] ).property('currentUser.login') - viewSearch: (params) -> - @set('content', Travis.Repo.search(params.search)) + viewSearch: (phrase) -> + @set('search', phrase) + @set('content', Travis.Repo.search(phrase)) searchObserver: (-> search = @get('search') if search @searchFor search - else - @activate 'recent' - 'recent' ).observes('search') searchFor: (phrase) -> Ember.run.cancel(@searchLater) if @searchLater @searchLater = Ember.run.later(this, (-> - @activate 'search', search: phrase + @transitionTo('index.search', phrase) ), 500) noReposMessage: (-> diff --git a/assets/scripts/app/controllers/request.coffee b/assets/scripts/app/controllers/request.coffee index e825c410..57d1d279 100644 --- a/assets/scripts/app/controllers/request.coffee +++ b/assets/scripts/app/controllers/request.coffee @@ -19,3 +19,13 @@ Travis.RequestController = Ember.ObjectController.extend else 'Rejected' ).property('isAccepted') + + message: (-> + message = @get('model.message') + if Travis.features.pro && message == "private repository" + '' + else + message + ).property('model.message') + + diff --git a/assets/scripts/app/controllers/settings.coffee b/assets/scripts/app/controllers/settings.coffee index e4e0e0bb..d090beea 100644 --- a/assets/scripts/app/controllers/settings.coffee +++ b/assets/scripts/app/controllers/settings.coffee @@ -12,6 +12,7 @@ Travis.SettingsIndexController = Em.ObjectController.extend @set('settings.maximum_number_of_builds_valid', 'invalid') ).observes('settings.maximum_number_of_builds') - save: -> - @get('model').saveSettings(@get('settings')).then null, -> - Travis.flash(error: 'There was an error while saving settings. Please try again.') + actions: + save: -> + @get('model').saveSettings(@get('settings')).then null, -> + Travis.flash(error: 'There was an error while saving settings. Please try again.') diff --git a/assets/scripts/app/helpers.coffee b/assets/scripts/app/helpers.coffee index 98608e18..5c5b4f46 100644 --- a/assets/scripts/app/helpers.coffee +++ b/assets/scripts/app/helpers.coffee @@ -2,3 +2,4 @@ require 'helpers/handlebars' require 'helpers/helpers' require 'helpers/urls' require 'helpers/status_image_formatter' +require 'helpers/github_url_properties' diff --git a/assets/scripts/app/helpers/github_url_properties.coffee b/assets/scripts/app/helpers/github_url_properties.coffee new file mode 100644 index 00000000..6a19e21c --- /dev/null +++ b/assets/scripts/app/helpers/github_url_properties.coffee @@ -0,0 +1,8 @@ +Travis.GithubUrlProperties = Ember.Mixin.create + urlGithubCommit: (-> + Travis.Urls.githubCommit(@get('repo.slug'), @get('commit.sha')) + ).property('repo.slug', 'commit.sha') + + urlGithubPullRequest: (-> + Travis.Urls.githubPullRequest(@get('repo.slug'), @get('build.pullRequestNumber')) + ).property('repo.slug', 'build.pullRequestNumber') diff --git a/assets/scripts/app/helpers/handlebars.coffee b/assets/scripts/app/helpers/handlebars.coffee index bc555d96..98901e6a 100644 --- a/assets/scripts/app/helpers/handlebars.coffee +++ b/assets/scripts/app/helpers/handlebars.coffee @@ -1,5 +1,3 @@ -require 'ext/ember/bound_helper' - safe = (string) -> new Handlebars.SafeString(string) @@ -50,6 +48,7 @@ Ember.Handlebars.registerHelper('label', (options) -> options.hash.for = id options.hashTypes.for = 'STRING' options.hashContexts.for = this + options.fn = Ember.Handlebars.compile("{{view.content}}") Ember.Handlebars.helpers.view.call(this, view, options) ) @@ -112,7 +111,7 @@ Travis.ErrorsView = Ember.View.extend ).property('@errors') show: Ember.computed.notEmpty('errors.[]') -Ember.Handlebars.helper('travis-errors', (name, options) -> +Ember.Handlebars.registerHelper('travis-errors', (name, options) -> errors = @get('errors').for(name) view = Travis.ErrorsView.create( controller: this @@ -125,7 +124,7 @@ Ember.Handlebars.helper('travis-errors', (name, options) -> Handlebars.registerHelper 'tipsy', (text, tip) -> safe '' + text + '' -Ember.registerBoundHelper 'capitalize', (value, options) -> +Ember.Handlebars.registerBoundHelper 'capitalize', (value, options) -> if value? safe $.capitalize(value) else @@ -140,10 +139,10 @@ Ember.Handlebars.helper('githubCommitLink', (slug, commitSha) -> safe '' + sha + '' ) -Ember.registerBoundHelper 'formatTime', (value, options) -> +Ember.Handlebars.registerBoundHelper 'formatTime', (value, options) -> safe Travis.Helpers.timeAgoInWords(value) || '-' -Ember.registerBoundHelper 'formatDuration', (duration, options) -> +Ember.Handlebars.registerBoundHelper 'formatDuration', (duration, options) -> safe Travis.Helpers.timeInWords(duration) Ember.Handlebars.helper('formatCommit', (commit) -> @@ -153,16 +152,16 @@ Ember.Handlebars.helper('formatCommit', (commit) -> Ember.Handlebars.helper 'formatSha', (sha) -> safe Travis.Helpers.formatSha(sha) -Ember.registerBoundHelper 'pathFrom', (url, options) -> +Ember.Handlebars.registerBoundHelper 'pathFrom', (url, options) -> safe Travis.Helpers.pathFrom(url) Ember.Handlebars.helper 'formatMessage', (message, options) -> safe Travis.Helpers.formatMessage(message, options.hash) -Ember.registerBoundHelper 'formatConfig', (config, options) -> +Ember.Handlebars.registerBoundHelper 'formatConfig', (config, options) -> safe Travis.Helpers.formatConfig(config) -Ember.registerBoundHelper 'shortCompareShas', (url, options) -> +Ember.Handlebars.registerBoundHelper 'shortCompareShas', (url, options) -> path = Travis.Helpers.pathFrom(url) if path.indexOf('...') >= 0 shas = path.split('...') @@ -170,7 +169,7 @@ Ember.registerBoundHelper 'shortCompareShas', (url, options) -> else path -Ember.registerBoundHelper 'formatLog', (log, options) -> +Ember.Handlebars.registerBoundHelper 'formatLog', (log, options) -> parentView = @get 'parentView' repo = parentView.get(options.repo) item = parentView.get(options.item) diff --git a/assets/scripts/app/helpers/urls.coffee b/assets/scripts/app/helpers/urls.coffee index cda9bbc5..9e7d5fbc 100644 --- a/assets/scripts/app/helpers/urls.coffee +++ b/assets/scripts/app/helpers/urls.coffee @@ -21,10 +21,18 @@ "#{Travis.config.source_endpoint}/#{slug}/settings/hooks#travis_minibucket" statusImage: (slug, branch) -> - "#{location.protocol}//#{location.host}/#{slug}.svg" + if branch then "?branch=#{encodeURIComponent(branch)}" else '' + if Travis.config.pro + token = Travis.__container__.lookup('controller:currentUser').get('token') + "#{location.protocol}//#{location.host}/#{slug}.svg?token=#{token}" + if branch then "&branch=#{branch}" else '' + else + "#{location.protocol}//#{location.host}/#{slug}.svg" + if branch then "?branch=#{encodeURIComponent(branch)}" else '' ccXml: (slug) -> - "#{Travis.config.api_endpoint}/repos/#{slug}/cc.xml" + if Travis.config.pro + token = Travis.__container__.lookup('controller:currentUser').get('token') + "##{Travis.config.api_endpoint}/repos/#{slug}/cc.xml?token=#{token}" + else + "#{Travis.config.api_endpoint}/repos/#{slug}/cc.xml" email: (email) -> "mailto:#{email}" diff --git a/assets/scripts/app/models/account.coffee b/assets/scripts/app/models/account.coffee index 513782db..f936df1d 100644 --- a/assets/scripts/app/models/account.coffee +++ b/assets/scripts/app/models/account.coffee @@ -5,6 +5,8 @@ require 'travis/model' name: Ember.attr('string') type: Ember.attr('string') _reposCount: Ember.attr(Number, key: 'repos_count') + subscribed: Ember.attr(Boolean) + education: Ember.attr(Boolean) urlGithub: (-> "#{Travis.config.source_endpoint}/#{@get('login')}" diff --git a/assets/scripts/app/models/build.coffee b/assets/scripts/app/models/build.coffee index a5fb1809..a83fcf91 100644 --- a/assets/scripts/app/models/build.coffee +++ b/assets/scripts/app/models/build.coffee @@ -23,7 +23,14 @@ require 'travis/model' jobs: Ember.hasMany('Travis.Job') config: (-> - Travis.Helpers.compact(@get('_config')) + console.log('config') + if config = @get('_config') + Travis.Helpers.compact(config) + else + return if @get('isFetchingConfig') + @set 'isFetchingConfig', true + + @reload() ).property('_config') # TODO add eventType to the api for api build requests @@ -92,12 +99,6 @@ require 'travis/model' requeue: -> Travis.ajax.post "/builds/#{@get('id')}/restart" - isPropertyLoaded: (key) -> - if ['_duration', '_finishedAt'].contains(key) && !@get('isFinished') - return true - else - @_super(key) - formattedFinishedAt: (-> if finishedAt = @get('finishedAt') moment(finishedAt).format('lll') diff --git a/assets/scripts/app/models/env_var.coffee b/assets/scripts/app/models/env_var.coffee index 5ddd444c..168df98f 100644 --- a/assets/scripts/app/models/env_var.coffee +++ b/assets/scripts/app/models/env_var.coffee @@ -6,11 +6,3 @@ Travis.EnvVar = Travis.Model.extend public: Ember.attr('boolean') repo: Ember.belongsTo('Travis.Repo', key: 'repository_id') - - isPropertyLoaded: (key) -> - if key == 'value' - return true - else - @_super(key) - - diff --git a/assets/scripts/app/models/job.coffee b/assets/scripts/app/models/job.coffee index 92a711fb..ec8d3b00 100644 --- a/assets/scripts/app/models/job.coffee +++ b/assets/scripts/app/models/job.coffee @@ -42,7 +42,13 @@ require 'travis/model' ).property('repositorySlug') config: (-> - Travis.Helpers.compact(@get('_config')) + if config = @get('_config') + Travis.Helpers.compact(config) + else + return if @get('isFetchingConfig') + @set 'isFetchingConfig', true + + @reload() ).property('_config') isFinished: (-> @@ -113,14 +119,6 @@ require 'travis/model' @unsubscribe() if @get('state') == 'finished' && Travis.pusher ).observes('state') - isPropertyLoaded: (key) -> - if ['_finishedAt'].contains(key) && !@get('isFinished') - return true - else if key == '_startedAt' && @get('state') == 'created' - return true - else - @_super(key) - isFinished: (-> @get('state') in ['passed', 'failed', 'errored', 'canceled'] ).property('state') @@ -139,6 +137,10 @@ require 'travis/model' true ).property() + slug: (-> + "#{@get('repo.slug')} ##{@get('number')}" + ).property() + @Travis.Job.reopenClass queued: -> filtered = Ember.FilteredRecordArray.create( diff --git a/assets/scripts/app/models/log.coffee b/assets/scripts/app/models/log.coffee index ef9b396e..6056731f 100644 --- a/assets/scripts/app/models/log.coffee +++ b/assets/scripts/app/models/log.coffee @@ -6,9 +6,6 @@ require 'travis/log_chunks' isLoaded: false length: 0 - init: -> - @setParts() - fetchMissingParts: (partNumbers, after) -> return if @get('notStarted') @@ -27,31 +24,31 @@ require 'travis/log_chunks' for part in parts @append part - setParts: -> - if parts = @get('parts') - parts.destroy() + parts: (-> + #if Travis.config.pusher_log_fallback + # Travis.LogChunks.create(content: [], missingPartsCallback: => @fetchMissingParts.apply(this, arguments)) + #else + Ember.ArrayProxy.create(content: []) + ).property() - if Travis.config.pusher_log_fallback - parts = Travis.LogChunks.create(content: [], missingPartsCallback: => @fetchMissingParts.apply(this, arguments)) - else - parts = Ember.ArrayProxy.create(content: []) - - @set 'parts', parts - # @set 'parts', Travis.ChunkBuffer.create(content: []) + clearParts: -> + parts = @get('parts') + parts.set('content', []) fetch: -> console.log 'log model: fetching log' if Log.DEBUG - @setParts() + @clearParts() handlers = json: (json) => @loadParts(json['log']['parts']) text: (text) => @loadText(text) Travis.Log.Request.create(id: id, handlers: handlers).run() if id = @get('job.id') clear: -> - @setParts() + @clearParts() @incrementProperty('version') append: (part) -> + return if @get('parts').isDestroying || @get('parts').isDestroyed @get('parts').pushObject(part) loadParts: (parts) -> @@ -75,6 +72,9 @@ Travis.Log.Request = Em.Object.extend success: (body, status, xhr) => Ember.run(this, -> @handle(body, status, xhr)) handle: (body, status, xhr) -> + if Travis.config.pro + Travis.Job.find(@get('id')).get('log').set('token', xhr.getResponseHeader('X-Log-Access-Token')) + if xhr.status == 204 $.ajax(url: @redirectTo(xhr), type: 'GET', success: @handlers.text) else if @isJson(xhr, body) diff --git a/assets/scripts/app/models/repo.coffee b/assets/scripts/app/models/repo.coffee index aa8c1e99..2e9a1cd0 100644 --- a/assets/scripts/app/models/repo.coffee +++ b/assets/scripts/app/models/repo.coffee @@ -24,6 +24,9 @@ require 'travis/model' } ).property('lastBuildId', 'lastBuildNumber') + withLastBuild: -> + @filter( (repo) -> repo.get('lastBuildId') ) + sshKey: (-> Travis.SshKey.find(@get('id')) ) diff --git a/assets/scripts/app/models/ssh_key.coffee b/assets/scripts/app/models/ssh_key.coffee index 59f05b19..40d83fb0 100644 --- a/assets/scripts/app/models/ssh_key.coffee +++ b/assets/scripts/app/models/ssh_key.coffee @@ -3,11 +3,3 @@ Travis.SshKey = Travis.Model.extend value: Ember.attr('string') description: Ember.attr('string') fingerprint: Ember.attr('string') - - isPropertyLoaded: (key) -> - if key == 'value' - return true - else - @_super(key) - - diff --git a/assets/scripts/app/pusher.coffee b/assets/scripts/app/pusher.coffee index 5cc394b9..74802a85 100644 --- a/assets/scripts/app/pusher.coffee +++ b/assets/scripts/app/pusher.coffee @@ -2,10 +2,17 @@ Travis.Pusher = (config) -> @init(config) this -$.extend Travis.Pusher, - CHANNELS: ['common'] - CHANNEL_PREFIX: '' - ENCRYPTED: false +if Travis.config.pro + $.extend Travis.Pusher, + CHANNELS: [] + CHANNEL_PREFIX: 'private-' + ENCRYPTED: true + KEY: '' +else + $.extend Travis.Pusher, + CHANNELS: ['common'] + CHANNEL_PREFIX: '' + ENCRYPTED: false $.extend Travis.Pusher.prototype, active_channels: [] @@ -101,3 +108,73 @@ $.extend Travis.Pusher.prototype, ignoreMessage: (message) -> message.indexOf('Existing subscription') == 0 or message.indexOf('No current subscription') == 0 +pusher_host = $('meta[name="travis.pusher_host"]').attr('value') +pusher_path = $('meta[name="travis.pusher_path"]').attr('value') + +Pusher.SockJSTransport.isSupported = -> false if pusher_host != 'ws.pusherapp.com' + +if Travis.config.pro + Pusher.channel_auth_transport = 'bulk_ajax' + + Pusher.authorizers.bulk_ajax = (socketId, _callback) -> + channels = Travis.pusher.pusher.channels + channels.callbacks ||= [] + + name = this.channel.name + names = $.keys(channels.channels) + + channels.callbacks.push (auths) -> + _callback(false, auth: auths[name]) + + unless channels.fetching + channels.fetching = true + Travis.ajax.post Pusher.channel_auth_endpoint, { socket_id: socketId, channels: names }, (data) -> + channels.fetching = false + callback(data.channels) for callback in channels.callbacks + + + Pusher.getDefaultStrategy = (config) -> + [ + [":def", "ws_options", { + hostUnencrypted: config.wsHost + ":" + config.wsPort + (pusher_path && "/#{pusher_path}" || ''), + hostEncrypted: config.wsHost + ":" + config.wssPort + (pusher_path && "/#{pusher_path}" || '') + path: config.path + }], + [":def", "sockjs_options", { + hostUnencrypted: config.httpHost + ":" + config.httpPort, + hostEncrypted: config.httpHost + ":" + config.httpsPort + }], + [":def", "timeouts", { + loop: true, + timeout: 15000, + timeoutLimit: 60000 + }], + + [":def", "ws_manager", [":transport_manager", { + lives: 2, + minPingDelay: 10000, + maxPingDelay: config.activity_timeout + }]], + + [":def_transport", "ws", "ws", 3, ":ws_options", ":ws_manager"], + [":def_transport", "flash", "flash", 2, ":ws_options", ":ws_manager"], + [":def_transport", "sockjs", "sockjs", 1, ":sockjs_options"], + [":def", "ws_loop", [":sequential", ":timeouts", ":ws"]], + [":def", "flash_loop", [":sequential", ":timeouts", ":flash"]], + [":def", "sockjs_loop", [":sequential", ":timeouts", ":sockjs"]], + + [":def", "strategy", + [":cached", 1800000, + [":first_connected", + [":if", [":is_supported", ":ws"], [ + ":best_connected_ever", ":ws_loop", [":delayed", 2000, [":sockjs_loop"]] + ], [":if", [":is_supported", ":flash"], [ + ":best_connected_ever", ":flash_loop", [":delayed", 2000, [":sockjs_loop"]] + ], [ + ":sockjs_loop" + ] + ]] + ] + ] + ] + ] diff --git a/assets/scripts/app/routes.coffee b/assets/scripts/app/routes.coffee index 2ce50a2e..838b0252 100644 --- a/assets/scripts/app/routes.coffee +++ b/assets/scripts/app/routes.coffee @@ -18,9 +18,22 @@ Travis.Route = Ember.Route.extend @_super.apply(this, arguments) signedIn: -> - @controllerFor('currentUser').get('content') + @controllerFor('currentUser').get('model') + + needsAuth: (-> + # on pro, we need to auth on every route + Travis.config.pro + ).property() Travis.ApplicationRoute = Travis.Route.extend + needsAuth: false + + renderTemplate: -> + if Travis.config.pro + $('body').addClass('pro') + + @_super.apply(this, arguments) + actions: redirectToGettingStarted: -> # do nothing, we handle it only in index path @@ -43,14 +56,21 @@ Travis.ApplicationRoute = Travis.Route.extend if transition = @auth.get('afterSignInTransition') @auth.set('afterSignInTransition', null) transition.retry() + else + @transitionTo('index') afterSignOut: -> - @transitionTo('index.current') + if Travis.config.pro + @transitionTo('auth') + else + @transitionTo('index') Travis.Router.map -> @resource 'index', path: '/', -> @resource 'getting_started' - @route 'current', path: '/' + @route 'recent' + @route 'my_repositories' + @route 'search', path: '/search/:phrase' @resource 'repo', path: '/:owner/:name', -> @route 'index', path: '/' @resource 'build', path: '/builds/:build_id' @@ -74,8 +94,9 @@ Travis.Router.map -> @route 'auth', path: '/auth' @resource 'profile', path: '/profile', -> - @resource 'account', path: '/:login' - @route 'info', path: '/info' + @resource 'accounts', path: '/', -> + @resource 'account', path: '/:login' + @route 'info', path: '/info' @route 'notFound', path: "/*path" @@ -129,8 +150,8 @@ Travis.GettingStartedRoute = Travis.Route.extend Travis.SimpleLayoutRoute = Travis.Route.extend setupController: -> $('body').attr('id', 'home') - @container.lookup('controller:repos').activate() - @container.lookup('controller:application').connectLayout 'simple' + toActivate = if @signedIn() then 'owned' else 'recent' + @container.lookup('controller:repos').activate(toActivate) @_super.apply(this, arguments) renderTemplate: -> @@ -148,31 +169,60 @@ Travis.InsufficientOauthPermissionsRoute = Travis.SimpleLayoutRoute.extend existingUser = document.location.hash.match(/#existing[_-]user/) controller.set('existingUser', existingUser) -Travis.IndexCurrentRoute = Travis.Route.extend +Travis.IndexTabRoute = Travis.Route.extend renderTemplate: -> @render 'repo' @render 'build', into: 'repo' setupController: -> @_super.apply this, arguments - @currentRepoDidChange() @controllerFor('repo').activate('index') - @controllerFor('repos').addObserver('firstObject', this, 'currentRepoDidChange') + @controllerFor('repos').activate(@get('reposTabName')) - afterModel: -> - @controllerFor('repos').possiblyRedirectToGettingStartedPage() + @currentRepoDidChange() + @controllerFor('repos').addObserver('firstObject', this, 'currentRepoDidChange') deactivate: -> @controllerFor('repos').removeObserver('firstObject', this, 'currentRepoDidChange') currentRepoDidChange: -> - @controllerFor('repo').set('repo', @controllerFor('repos').get('firstObject')) + if repo = @controllerFor('repos').get('firstObject') + @controllerFor('repo').set('repo', repo) actions: redirectToGettingStarted: -> @transitionTo('getting_started') +Travis.IndexMyRepositoriesRoute = Travis.IndexTabRoute.extend + reposTabName: 'owned' + afterModel: -> + @controllerFor('repos').possiblyRedirectToGettingStartedPage() + +Travis.IndexRecentRoute = Travis.IndexTabRoute.extend + reposTabName: 'recent' + +Travis.IndexSearchRoute = Travis.IndexTabRoute.extend + renderTemplate: -> + @render 'repo' + @render 'build', into: 'repo' + + setupController: (controller, searchPhrase) -> + # TODO: this method is almost the same as _super, refactor this + @controllerFor('repo').activate('index') + @controllerFor('repos').activate('search', searchPhrase) + + @currentRepoDidChange() + @controllerFor('repos').addObserver('firstObject', this, 'currentRepoDidChange') + + model: (params) -> + params.phrase + + deactivate: -> + @_super.apply(this, arguments) + + @controllerFor('repos').set('search', undefined) + Travis.AbstractBuildsRoute = Travis.Route.extend renderTemplate: -> @render 'builds' @@ -187,7 +237,7 @@ Travis.AbstractBuildsRoute = Travis.Route.extend contentDidChange: -> path = @get('path') - @controllerFor('builds').set('content', @controllerFor('repo').get(path)) + @controllerFor('builds').set('model', @controllerFor('repo').get(path)) path: (-> type = @get('contentType') @@ -195,8 +245,19 @@ Travis.AbstractBuildsRoute = Travis.Route.extend ).property('contentType') Travis.BuildsRoute = Travis.AbstractBuildsRoute.extend(contentType: 'builds') -Travis.PullRequestsRoute = Travis.AbstractBuildsRoute.extend(contentType: 'pull_requests') Travis.BranchesRoute = Travis.AbstractBuildsRoute.extend(contentType: 'branches') +Travis.PullRequestsRoute = Travis.AbstractBuildsRoute.extend( + contentType: 'pull_requests' + + # TODO: it would be better to have separate controller for branches and PRs list + setupController: (controller, model) -> + @_super(controller, model) + + this.controllerFor('builds').set('isPullRequestsList', true) + + deactivate: -> + this.controllerFor('builds').set('isPullRequestsList', false) +) Travis.BuildRoute = Travis.Route.extend serialize: (model, params) -> @@ -208,18 +269,17 @@ Travis.BuildRoute = Travis.Route.extend model = Travis.Build.find(model) if model && !model.get repo = @controllerFor('repo') - repo.set('build', model) - repo.activate('build') + #repo.set('build', model) @controllerFor('build').set('build', model) - repo.set('build', model) + repo.activate('build') + #repo.set('build', model) model: (params) -> Travis.Build.fetch(params.build_id) deactivate: -> - repo = @controllerFor('repo') - repo.set('build', null) - repo.set('job', null) + @controllerFor('job').set('job', null) + @controllerFor('build').set('build', null) Travis.JobRoute = Travis.Route.extend serialize: (model, params) -> @@ -231,19 +291,19 @@ Travis.JobRoute = Travis.Route.extend model = Travis.Job.find(model) if model && !model.get repo = @controllerFor('repo') - repo.set('job', model) + @controllerFor('job').set('job', model) repo.activate('job') if build = model.get('build') @controllerFor('build').set('build', build) - repo.set('build', build) model: (params) -> Travis.Job.fetch(params.job_id) deactivate: -> - repo = @controllerFor('repo') - repo.set('job', null) + @controllerFor('build').set('build', null) + @controllerFor('job').set('job', null) + Travis.RepoIndexRoute = Travis.Route.extend setupController: (controller, model) -> @@ -258,8 +318,8 @@ Travis.RepoIndexRoute = Travis.Route.extend deactivate: -> repo = @controllerFor('repo') - repo.set('build', null) - repo.set('job', null) + @controllerFor('build').set('build', null) + @controllerFor('job').set('job', null) Travis.RepoRoute = Travis.Route.extend renderTemplate: -> @@ -280,6 +340,9 @@ Travis.RepoRoute = Travis.Route.extend slug = "#{params.owner}/#{params.name}" Travis.Repo.fetchBySlug(slug) + resetController: -> + @controllerFor('repo').deactivate() + actions: error: (error) -> # if error throwed has a slug (ie. it was probably repo not found) @@ -291,15 +354,25 @@ Travis.RepoRoute = Travis.Route.extend # bubble to the top return true +# Obviously Index route should be renamed to something +# like "main" or "home" +Travis.IndexIndexRoute = Travis.Route.extend + redirect: -> + target = if @signedIn() then 'my_repositories' else 'recent' + @transitionTo("index.#{target}") + Travis.IndexRoute = Travis.Route.extend renderTemplate: -> $('body').attr('id', 'home') - @render 'repos', outlet: 'left' + @_super.apply this, arguments + + @render 'repos', outlet: 'left', into: 'index' setupController: (controller)-> - @container.lookup('controller:repos').activate() - @container.lookup('controller:application').connectLayout 'home' + # TODO: this is redundant with my_repositories and recent routes + toActivate = if @signedIn() then 'owned' else 'recent' + @container.lookup('controller:repos').activate(toActivate) Travis.StatsRoute = Travis.Route.extend renderTemplate: -> @@ -307,42 +380,39 @@ Travis.StatsRoute = Travis.Route.extend @render 'stats' - setupController: -> - @container.lookup('controller:application').connectLayout('simple') - Travis.NotFoundRoute = Travis.Route.extend renderTemplate: -> $('body').attr('id', 'not-found') @render 'not_found' - setupController: -> - @container.lookup('controller:application').connectLayout('simple') - Travis.ProfileRoute = Travis.Route.extend needsAuth: true setupController: (controller, model) -> - @container.lookup('controller:application').connectLayout('profile') @controllerFor('accounts').set('model', model) + renderTemplate: -> + $('body').attr('id', 'profile') + @_super.apply(this, arguments) + @render 'loading', outlet: 'left', into: 'profile' + +Travis.AccountsRoute = Travis.Route.extend model: -> Travis.Account.fetch(all: true) renderTemplate: -> - $('body').attr('id', 'profile') - @render 'accounts', outlet: 'left' - @_super.apply(this, arguments) + @render 'profile_accounts', outlet: 'left', into: 'profile' -Travis.ProfileIndexRoute = Travis.Route.extend +Travis.AccountsIndexRoute = Travis.Route.extend redirect: -> # TODO: setting accounts model in ProfileRoute is wrong, but # at this stage it's better than what we had before - accounts = @modelFor('profile') + accounts = @modelFor('accounts') login = @controllerFor('currentUser').get('login') account = accounts.find (account) -> account.get('login') == login - @transitionTo 'account', account + @replaceWith 'account', account Travis.AccountRoute = Travis.Route.extend setupController: (controller, account) -> @@ -351,7 +421,7 @@ Travis.AccountRoute = Travis.Route.extend @controllerFor('profile').activate 'hooks' model: (params) -> - @modelFor('profile').find (account) -> account.get('login') == params.login + @modelFor('accounts').find (account) -> account.get('login') == params.login serialize: (account) -> if account && account.get @@ -359,30 +429,35 @@ Travis.AccountRoute = Travis.Route.extend else {} -Travis.ProfileInfoRoute = Travis.Route.extend +Travis.AccountsInfoRoute = Travis.Route.extend setupController: -> - @container.lookup('controller:profile').activate 'user' + user = @controllerFor('currentUser').get('model') + @controllerFor('account').set('model', user) + @controllerFor('profile').activate 'user' renderTemplate: -> - @render 'user' + @render 'accounts_info' Travis.AuthRoute = Travis.Route.extend + needsAuth: false + renderTemplate: -> $('body').attr('id', 'auth') @render 'auth.signin' - setupController: -> - @container.lookup('controller:application').connectLayout('simple') - deactivate: -> @controllerFor('auth').set('redirected', false) actions: afterSignIn: -> - @transitionTo('index.current') + @transitionTo('index') return true + redirect: -> + if @signedIn() + @transitionTo('index') + Travis.SettingsRoute = Travis.Route.extend needsAuth: true setupController: (controller, model) -> @@ -403,7 +478,7 @@ Travis.SshKeyRoute = Travis.Route.extend model: (params) -> repo = @modelFor('repo') self = this - Travis.SshKey.fetch(repo.get('id')).then ( (result) -> result ), (xhr) -> + Travis.SshKey.fetch(repo.get('id')).then ( (result) -> result unless result.get('isNew') ), (xhr) -> if xhr.status == 404 # if there is no model, just return null. I'm not sure if this is the # best answer, maybe we should just redirect to different route, like @@ -422,3 +497,8 @@ Travis.SshKeyRoute = Travis.Route.extend if @defaultKey controller.set('defaultKey', @defaultKey) @defaultKey = null + + deactivate: -> + @_super.apply(this, arguments) + + @controllerFor('ssh_key').send('cancel') diff --git a/assets/scripts/app/templates/accounts.hbs b/assets/scripts/app/templates/accounts.hbs new file mode 100644 index 00000000..c24cd689 --- /dev/null +++ b/assets/scripts/app/templates/accounts.hbs @@ -0,0 +1 @@ +{{outlet}} diff --git a/assets/scripts/app/templates/application.hbs b/assets/scripts/app/templates/application.hbs new file mode 100644 index 00000000..c24cd689 --- /dev/null +++ b/assets/scripts/app/templates/application.hbs @@ -0,0 +1 @@ +{{outlet}} diff --git a/assets/scripts/app/templates/builds/list.hbs b/assets/scripts/app/templates/builds/list.hbs index ea2a408a..221b16eb 100644 --- a/assets/scripts/app/templates/builds/list.hbs +++ b/assets/scripts/app/templates/builds/list.hbs @@ -10,7 +10,7 @@
{{#if job.id}}
@@ -45,7 +44,7 @@
{{#unless view.required}}
-
+
{{else}}
Allowed Failures are items in your build matrix that are allowed to diff --git a/assets/scripts/app/templates/jobs/log.hbs b/assets/scripts/app/templates/jobs/log.hbs index 1c1ffb84..0c74f7b8 100644 --- a/assets/scripts/app/templates/jobs/log.hbs +++ b/assets/scripts/app/templates/jobs/log.hbs @@ -1,5 +1,5 @@ {{#if view.log.isLoaded}} - {{view Travis.PreView jobBinding="view.job" logBinding="view.log"}} + {{view 'pre' job=view.job log=view.log}} {{else}}
Loading
diff --git a/assets/scripts/app/templates/jobs/pre.hbs b/assets/scripts/app/templates/jobs/pre.hbs
index 3fdd42af..290b7c36 100644
--- a/assets/scripts/app/templates/jobs/pre.hbs
+++ b/assets/scripts/app/templates/jobs/pre.hbs
@@ -1,5 +1,5 @@
- {{view Travis.AnnotationsView annotationsBinding="view.annotations"}}
+ {{view 'annotations' annotations=view.annotations}}
- {{view Travis.LogView jobBinding="job"}}
+ {{view 'log' job=job}}
-
+
- To Top
+ To Top
{{#if view.job.sponsor.name}}
diff --git a/assets/scripts/app/templates/jobs/show.hbs b/assets/scripts/app/templates/jobs/show.hbs index 9d54e7d6..a0139070 100644 --- a/assets/scripts/app/templates/jobs/show.hbs +++ b/assets/scripts/app/templates/jobs/show.hbs @@ -62,9 +62,9 @@
diff --git a/assets/scripts/app/templates/layouts/flash.hbs b/assets/scripts/app/templates/layouts/flash.hbs
index ccbabee6..193d0d8c 100644
--- a/assets/scripts/app/templates/layouts/flash.hbs
+++ b/assets/scripts/app/templates/layouts/flash.hbs
@@ -1,6 +1,6 @@
{{#each flash in controller}}
{{#view Travis.FlashItemView flashBinding="flash"}}
{{{flash.message}}} - + {{/view}} {{/each}} diff --git a/assets/scripts/app/templates/layouts/home.hbs b/assets/scripts/app/templates/layouts/home.hbs index 4e6fc0fe..ff2aa177 100644 --- a/assets/scripts/app/templates/layouts/home.hbs +++ b/assets/scripts/app/templates/layouts/home.hbs @@ -3,10 +3,16 @@
- {{outlet left}}
+ {{outlet "left"}}
{{render "flash"}}
- {{outlet}}
+ {{yield}}
+
+{{#if config.pro}}
+
+ {{render "layouts/sidebar"}}
+
+{{/if}}
diff --git a/assets/scripts/app/templates/layouts/profile.hbs b/assets/scripts/app/templates/layouts/profile.hbs
index 2a908308..736b3899 100644
--- a/assets/scripts/app/templates/layouts/profile.hbs
+++ b/assets/scripts/app/templates/layouts/profile.hbs
@@ -3,16 +3,16 @@
- {{outlet left}}
+ {{outlet "left"}}
{{render "flash"}}
- {{outlet main}}
+ {{yield}}
-
+
+
+
+
+{{#if tip}}
+
+
+{{/if}}
+
+{{#if config.pages_endpoint}}
+ {{view templateName="layouts/support"}}
+{{/if}}
+
+{{render "runningJobs"}}
+
+{{view Travis.QueueView}}
diff --git a/assets/scripts/app/templates/layouts/simple.hbs b/assets/scripts/app/templates/layouts/simple.hbs
index cd930a31..839a526a 100644
--- a/assets/scripts/app/templates/layouts/simple.hbs
+++ b/assets/scripts/app/templates/layouts/simple.hbs
@@ -4,5 +4,5 @@
Tip:+ +{{{tip}}} +
{{render "flash"}}
- {{outlet main}}
+ {{yield}}
diff --git a/assets/scripts/app/templates/layouts/support.hbs b/assets/scripts/app/templates/layouts/support.hbs
new file mode 100644
index 00000000..fe2557ab
--- /dev/null
+++ b/assets/scripts/app/templates/layouts/support.hbs
@@ -0,0 +1,12 @@
+
+
+
diff --git a/assets/scripts/app/templates/layouts/top.hbs b/assets/scripts/app/templates/layouts/top.hbs
index 7f81285d..fa57098e 100644
--- a/assets/scripts/app/templates/layouts/top.hbs
+++ b/assets/scripts/app/templates/layouts/top.hbs
@@ -1,4 +1,4 @@
-{{#link-to "index.current"}}
+{{#link-to "index"}}
How can we help?+
Travis |