From 2450f9fe9d1bbadb7ab7c839d49d4d91bbea7c1e Mon Sep 17 00:00:00 2001 From: Henrik Hodne Date: Wed, 12 Feb 2014 09:43:21 -0600 Subject: [PATCH] Revert previous revert I found the commit that caused the bug that caused me to do the last revert. I'm therefore reverting the previous revert and I will be committing a revert that reverts the commit that introduced the bug. See next commit. This reverts commit db2d38a7aff246cea2d748d210ea118a67dc4945. --- assets/scripts/app/auth.coffee | 2 +- assets/scripts/app/components.coffee | 16 +- assets/scripts/app/controllers.coffee | 12 + assets/scripts/app/helpers/handlebars.coffee | 287 ++++++++++++++++++ assets/scripts/app/models/hook.coffee | 10 + assets/scripts/app/models/repo.coffee | 12 +- assets/scripts/app/routes.coffee | 164 +++++----- .../templates/components/travis-switch.hbs | 2 +- .../scripts/app/templates/index_loading.hbs | 1 - .../app/templates/profile/tabs/hooks.hbs | 2 +- .../scripts/app/templates/repos/not_found.hbs | 3 - assets/scripts/app/templates/repos/show.hbs | 1 - .../app/templates/repos/show/tools.hbs | 6 + assets/scripts/app/views.coffee | 1 + assets/scripts/app/views/repo/show.coffee | 13 + assets/scripts/lib/travis/ajax.coffee | 3 +- .../spec/integration/routes_spec.coffee | 22 +- assets/scripts/spec/support/mocks.coffee | 3 +- assets/styles/app/loading.sass | 2 +- assets/styles/components/travis-switch.sass | 6 +- assets/styles/profile/hooks.sass | 4 +- 21 files changed, 477 insertions(+), 95 deletions(-) delete mode 100644 assets/scripts/app/templates/index_loading.hbs delete mode 100644 assets/scripts/app/templates/repos/not_found.hbs diff --git a/assets/scripts/app/auth.coffee b/assets/scripts/app/auth.coffee index 40a47c79..46dda80f 100644 --- a/assets/scripts/app/auth.coffee +++ b/assets/scripts/app/auth.coffee @@ -71,7 +71,7 @@ try router.send('afterSignIn') catch e - throw e unless e =~ /There are no active handlers/ + throw e unless e =~ /There are no active handlers/ || e =~ /Can't trigger action "afterSignIn/ @refreshUserData(data.user) refreshUserData: (user) -> diff --git a/assets/scripts/app/components.coffee b/assets/scripts/app/components.coffee index da423edd..09a177fb 100644 --- a/assets/scripts/app/components.coffee +++ b/assets/scripts/app/components.coffee @@ -1,9 +1,19 @@ Travis.TravisSwitchComponent = Ember.Component.extend tagName: 'a' classNames: ['travis-switch'] - classNameBindings: ['active'] + classNameBindings: ['_active:active'] - activeBinding: 'target.active' + # TODO: how to handle overriding properties to + # avoid naming it _action? + _active: (-> + @get('target.active') || @get('active') + ).property('target.active', 'active') click: -> - @sendAction('action', @get('target')) + if target = @get('target') + @set('target.active', !@get('target.active')) + else + @set('active', !@get('active')) + # allow for bindings to propagate + Ember.run.next this, -> + @sendAction('action', target) diff --git a/assets/scripts/app/controllers.coffee b/assets/scripts/app/controllers.coffee index f1b4f520..488e3eb7 100644 --- a/assets/scripts/app/controllers.coffee +++ b/assets/scripts/app/controllers.coffee @@ -48,6 +48,18 @@ Travis.FirstSyncController = Em.Controller.extend isSyncing: Ember.computed.alias('user.isSyncing') +Travis.IndexErrorController = Em.Controller.extend() + +Travis.RepoSettingsTabController = Em.ObjectController.extend() +Travis.RepoSettingsController = Em.ObjectController.extend + needs: ['repoSettingsTab'] + tab: Ember.computed.alias('controllers.repoSettingsTab.model.tab') + settings: Ember.computed.alias('model.settings') + + save: -> + @get('model').saveSettings(@get('settings')).then null, -> + Travis.flash(error: 'There was an error while saving settings. Please try again.') + require 'controllers/accounts' require 'controllers/build' require 'controllers/builds' diff --git a/assets/scripts/app/helpers/handlebars.coffee b/assets/scripts/app/helpers/handlebars.coffee index 8dfda033..1074da90 100644 --- a/assets/scripts/app/helpers/handlebars.coffee +++ b/assets/scripts/app/helpers/handlebars.coffee @@ -3,6 +3,293 @@ require 'ext/ember/bound_helper' safe = (string) -> new Handlebars.SafeString(string) +Travis.Tab = Ember.Object.extend + show: -> + @get('tabs').forEach( (t) -> t.hide() ) + @set('visible', true) + + hide: -> + @set('visible', false) + +Travis.TabsView = Ember.View.extend + tabBinding: 'controller.tab' + tabsBinding: 'controller.tabs' + + tabDidChange: (-> + @activateTab(@get('tab')) + ).observes('tab') + + tabsDidChange: (-> + tab = @get('tab') + if tab + @activateTab(tab) + else if @get('tabs.length') + @activateTab(@get('tabs.firstObject.id')) + ).observes('tabs.length', 'tabs') + + activateTab: (tabId) -> + tab = @get('tabs').findBy('id', tabId) + + return unless tab + + tab.show() unless tab.get('visible') + + # TODO: remove hardcoded link + layout: Ember.Handlebars.compile( + '' + + '{{yield}}') + +Travis.TabView = Ember.View.extend + attributeBindings: ['style'] + + style: (-> + if !@get('tab.visible') + 'display: none' + ).property('tab.visible') + +Ember.Handlebars.registerHelper('travis-tab', (id, name, options) -> + controller = this + controller.set('tabs', []) unless controller.get('tabs') + + tab = Travis.Tab.create(id: id, name: name, tabs: controller.get('tabs')) + + view = Travis.TabView.create( + controller: this + tab: tab + ) + + controller = this + Ember.run.schedule('afterRender', -> + if controller.get('tabs.length') == 0 + tab.show() + controller.get('tabs').pushObject(tab) + ) + + Ember.Handlebars.helpers.view.call(this, view, options) +) + + +Ember.Handlebars.registerHelper('travis-tabs', (options) -> + template = options.fn + delete options.fn + + @set('tabs', []) + + view = Travis.TabsView.create( + controller: this + template: template + ) + + Ember.Handlebars.helpers.view.call(this, view, options) +) + +Travis.SettingsMultiplierView = Ember.CollectionView.extend() + +createObjects = (path, offset) -> + segments = path.split('.') + if segments.length > offset + for i in [1..(segments.length - offset)] + path = segments.slice(0, i).join('.') + if Ember.isNone(Ember.get(this, path)) + Ember.set(this, path, {}) + + return segments + +Ember.Handlebars.registerHelper('settings-multiplier', (path, options) -> + template = options.fn + delete options.fn + + parentsPath = getSettingsPath(options.data.view) + if parentsPath && parentsPath != '' + path = parentsPath + '.' + path + + createObjects.call(this, path, 1) + + if Ember.isNone(@get(path)) + collection = [{}] + @set(path, collection) + + + itemViewClass = Ember.View.extend( + template: template, + controller: this, + tagName: 'li', + multiplier: true + ) + + view = Travis.SettingsMultiplierView.create( + contentBinding: 'controller.' + path + controller: this + tagName: 'ul' + itemViewClass: itemViewClass + fields: [] + settingsPath: path + ) + + view.addObserver('content.length', -> + if @get('content.length') == 0 + @get('content').pushObject({}) + ) + + Ember.Handlebars.helpers.view.call(this, view, options) +) + +Travis.FormSettingsView = Ember.View.extend Ember.TargetActionSupport, + target: Ember.computed.alias('controller') + actionContext: Ember.computed.alias('context'), + action: 'submit' + tagName: 'form' + submit: (event) -> + event.preventDefault() + @triggerAction() + + +Ember.Handlebars.registerHelper('settings-form', (path, options) -> + if arguments.length == 1 + options = path + path = 'settings' + + view = Travis.FormSettingsView.create( + template: options.fn + controller: this + settingsPath: path + ) + + delete options.fn + + Ember.Handlebars.helpers.view.call(this, view, options) +) + +Ember.Handlebars.helper('settings-select', (options) -> + view = options.data.view + optionValues = options.hash.options + delete options.hash.options + + originalPath = options.hash.value + + parentsPath = getSettingsPath(view) + #TODO: such checks should also check parents, not only current context view + if !view.get('multiplier') && parentsPath && parentsPath != '' + originalPath = parentsPath + '.' + originalPath + + fullPath = originalPath + + if view.get('multiplier') + fullPath = 'view.content.' + fullPath + + createObjects.call(this, fullPath, 1) + + # TODO: setting a value here does not work and we still need + # a valueBinding in the view, I'm not sure why + options.hash.value = fullPath + + selectView = Ember.Select.create( + content: [''].pushObjects(optionValues.split(',')) + controller: this + valueBinding: 'controller.' + fullPath + ) + + Ember.Handlebars.helpers.view.call(this, selectView, options) +) + + + +Ember.Handlebars.helper('settings-remove-link', (options) -> + view = Ember.View.extend( + tagName: 'a' + attributeBindings: ['href', 'style'] + href: '#' + style: (-> + # TODO: do not assume that we're direct child + if @get('parentView.parentView.content.length') == 1 + 'display: none' + ).property('parentView.parentView.content.length') + template: Ember.Handlebars.compile('remove') + controller: this + click: (event) -> + event.preventDefault() + + if content = @get('parentView.content') + @get('parentView.parentView.content').removeObject(content) + ).create() + + Ember.Handlebars.helpers.view.call(this, view, options) +) + +Ember.Handlebars.registerHelper('settings-add-link', (path, options) -> + parentsPath = getSettingsPath(options.data.view) + if parentsPath && parentsPath != '' + path = parentsPath + '.' + path + + view = Ember.View.create( + tagName: 'a' + attributeBindings: ['href'] + href: '#' + template: options.fn + controller: this + click: (event) -> + event.preventDefault() + + if collection = @get('controller.' + path) + collection.pushObject({}) + ) + + Ember.Handlebars.helpers.view.call(this, view, options) +) + +getSettingsPath = (view) -> + settingsPaths = [] + if settingsPath = view.get('settingsPath') + settingsPaths.pushObject settingsPath + + parent = view + while parent = parent.get('parentView') + if settingsPath = parent.get('settingsPath') + settingsPaths.pushObject settingsPath + + return settingsPaths.reverse().join('.') + +Ember.Handlebars.helper('settings-input', (options) -> + view = options.data.view + + if options.hash.type == 'checkbox' + originalPath = options.hash.checked + else + originalPath = options.hash.value + + parentsPath = getSettingsPath(view) + #TODO: such checks should also check parents, not only current context view + if !view.get('multiplier') && parentsPath && parentsPath != '' + originalPath = parentsPath + '.' + originalPath + + fullPath = originalPath + + if view.get('multiplier') + fullPath = 'view.content.' + fullPath + + if options.hash.type != 'password' + createObjects.call(this, fullPath, 1) + else + createObjects.call(view, fullPath, 2) + content = view.get('content') + fullPath += ".value" + if Ember.isNone(Ember.get(content, originalPath)) + Ember.set(content, originalPath, {}) + Ember.set(content, originalPath + ".type", 'password') + + if options.hash.type == 'checkbox' + options.hash.checked = fullPath + else + options.hash.value = fullPath + Ember.Handlebars.helpers.input.call(this, options) +) + Handlebars.registerHelper 'tipsy', (text, tip) -> safe '' + text + '' diff --git a/assets/scripts/app/models/hook.coffee b/assets/scripts/app/models/hook.coffee index 677708d1..4126292b 100644 --- a/assets/scripts/app/models/hook.coffee +++ b/assets/scripts/app/models/hook.coffee @@ -27,3 +27,13 @@ require 'travis/model' return if @get('isSaving') @set 'active', !@get('active') @save() + + repo: (-> + # I don't want to make an ajax request for each repository showed in profile, + # especially, because most of them does not have any builds anyway. That's why + # I add an info which we have here to the store - this will allow to display + # a link to the repo and if more info is needed, it will be requested when the + # link is used + Travis.loadOrMerge(Travis.Repo, @getProperties('id', 'slug', 'name', 'ownerName'), skipIfExists: true) + Travis.Repo.find(@get('id')) + ).property('id') diff --git a/assets/scripts/app/models/repo.coffee b/assets/scripts/app/models/repo.coffee index f582fb10..3f94fc93 100644 --- a/assets/scripts/app/models/repo.coffee +++ b/assets/scripts/app/models/repo.coffee @@ -105,6 +105,13 @@ require 'travis/model' regenerateKey: (options) -> Travis.ajax.ajax '/repos/' + @get('id') + '/key', 'post', options + fetchSettings: -> + Travis.ajax.ajax('/repos/' + @get('id') + '/settings', 'get', forceAuth: true).then (data) -> + data['settings'] + + saveSettings: (settings) -> + Travis.ajax.ajax('/repos/' + @get('id') + '/settings', 'patch', data: { settings: settings }) + @Travis.Repo.reopenClass recent: -> @find() @@ -140,7 +147,10 @@ require 'travis/model' if repos.length > 0 repos[0] else - @fetch(slug: slug).then (repos) -> Ember.get(repos, 'firstObject') + @fetch(slug: slug).then (repos) -> + error = new Error('repo not found') + error.slug = slug + Ember.get(repos, 'firstObject') || throw(error) # buildURL: (slug) -> # if slug then slug else 'repos' diff --git a/assets/scripts/app/routes.coffee b/assets/scripts/app/routes.coffee index 711111a8..f277b20d 100644 --- a/assets/scripts/app/routes.coffee +++ b/assets/scripts/app/routes.coffee @@ -5,41 +5,9 @@ Ember.Router.reopen handleURL: (url) -> url = url.replace(/#.*?$/, '') - try - @_super(url) - catch error - if error.message.match(/No route matched the URL/) - @_super('/not-found') - else - throw(error) - -# TODO: don't reopen Ember.Route to add events, there should be -# a better way (like "parent" resource for everything inside map) -Ember.Route.reopen - _actions: - renderDefaultTemplate: -> - @renderDefaultTemplate() if @renderDefaultTemplate - - error: (error) -> - if error == 'needs-auth' - authController = @container.lookup('controller:auth') || @generateController('auth') - authController.set('redirected', true) - @transitionTo('auth') - else - throw(error) - - renderNoOwnedRepos: -> - @render('no_owned_repos', outlet: 'main') - - renderFirstSync: -> - @renderFirstSync() - - afterSignIn: (path) -> - @afterSignIn(path) - - afterSignOut: -> - @afterSignOut() + @_super(url) +Travis.Route = Ember.Route.extend afterSignIn: -> if transition = Travis.auth.get('afterSignInTransition') Travis.auth.set('afterSignInTransition', null) @@ -78,6 +46,37 @@ Ember.Route.reopen Travis.storeAfterSignInPath(path) @transitionTo('auth') +Travis.ApplicationRoute = Travis.Route.extend + actions: + renderDefaultTemplate: -> + @renderDefaultTemplate() if @renderDefaultTemplate + + error: (error) -> + if error == 'needs-auth' + authController = @container.lookup('controller:auth') || @generateController('auth') + authController.set('redirected', true) + @transitionTo('auth') + else + return true + + renderNoOwnedRepos: -> + @render('no_owned_repos', outlet: 'main') + + renderFirstSync: -> + @renderFirstSync() + + afterSignIn: (path) -> + @afterSignIn(path) + + afterSignOut: -> + @afterSignOut() + +Travis.Router.reopen + transitionTo: -> + this.container.lookup('controller:repo').set('lineNumber', null) + + @_super.apply this, arguments + Travis.Router.map -> @resource 'index', path: '/', -> @route 'current', path: '/' @@ -89,11 +88,15 @@ Travis.Router.map -> @resource 'pullRequests', path: '/pull_requests' @resource 'branches', path: '/branches' + # this can't be nested in repo, because we want a set of different + # templates rendered for settings (for example no "current", "builds", ... tabs) + @resource 'repo.settings', path: '/:owner/:name/settings', -> + @route 'tab', path: ':tab' + @route 'getting_started' @route 'first_sync' @route 'stats', path: '/stats' @route 'auth', path: '/auth' - @route 'notFound', path: '/not-found' @resource 'profile', path: '/profile', -> @route 'index', path: '/' @@ -101,6 +104,8 @@ Travis.Router.map -> @route 'index', path: '/' @route 'profile', path: '/profile' + @route 'notFound', path: "/*path" + Travis.SetupLastBuild = Ember.Mixin.create setupController: -> @repoDidLoad() @@ -111,9 +116,9 @@ Travis.SetupLastBuild = Ember.Mixin.create repo = @controllerFor('repo').get('repo') if repo && repo.get('isLoaded') && !repo.get('lastBuildId') Ember.run.next => - @render('builds/not_found', outlet: 'pane', into: 'repo') + @render('builds/not_found', into: 'repo', outlet: 'pane') -Travis.GettingStartedRoute = Ember.Route.extend +Travis.GettingStartedRoute = Travis.Route.extend setupController: -> $('body').attr('id', 'home') @container.lookup('controller:repos').activate() @@ -125,8 +130,8 @@ Travis.GettingStartedRoute = Ember.Route.extend @render 'repos', outlet: 'left' @_super.apply(this, arguments) -Travis.FirstSyncRoute = Ember.Route.extend - _actions: +Travis.FirstSyncRoute = Travis.Route.extend + actions: renderNoOwnedRepos: (->) # do nothing, we are showing first sync, so it's normal that there is # no owned repos @@ -141,10 +146,10 @@ Travis.FirstSyncRoute = Ember.Route.extend @render 'top', outlet: 'top' @_super.apply(this, arguments) -Travis.IndexCurrentRoute = Ember.Route.extend Travis.SetupLastBuild, +Travis.IndexCurrentRoute = Travis.Route.extend Travis.SetupLastBuild, renderTemplate: -> @render 'repo' - @render 'build', outlet: 'pane', into: 'repo' + @render 'build', into: 'repo', outlet: 'pane' setupController: -> @_super.apply this, arguments @@ -159,9 +164,9 @@ Travis.IndexCurrentRoute = Ember.Route.extend Travis.SetupLastBuild, currentRepoDidChange: -> @controllerFor('repo').set('repo', @controllerFor('repos').get('firstObject')) -Travis.AbstractBuildsRoute = Ember.Route.extend +Travis.AbstractBuildsRoute = Travis.Route.extend renderTemplate: -> - @render 'builds', outlet: 'pane', into: 'repo' + @render 'builds', into: 'repo', outlet: 'pane' setupController: -> @controllerFor('repo').activate(@get('contentType')) @@ -184,9 +189,9 @@ Travis.BuildsRoute = Travis.AbstractBuildsRoute.extend(contentType: 'builds') Travis.PullRequestsRoute = Travis.AbstractBuildsRoute.extend(contentType: 'pull_requests') Travis.BranchesRoute = Travis.AbstractBuildsRoute.extend(contentType: 'branches') -Travis.BuildRoute = Ember.Route.extend +Travis.BuildRoute = Travis.Route.extend renderTemplate: -> - @render 'build', outlet: 'pane', into: 'repo' + @render 'build', into: 'repo', outlet: 'pane' serialize: (model, params) -> id = if model.get then model.get('id') else model @@ -205,9 +210,9 @@ Travis.BuildRoute = Ember.Route.extend model: (params) -> Travis.Build.fetch(params.build_id) -Travis.JobRoute = Ember.Route.extend +Travis.JobRoute = Travis.Route.extend renderTemplate: -> - @render 'job', outlet: 'pane', into: 'repo' + @render 'job', into: 'repo', outlet: 'pane' serialize: (model, params) -> id = if model.get then model.get('id') else model @@ -228,15 +233,15 @@ Travis.JobRoute = Ember.Route.extend model: (params) -> Travis.Job.fetch(params.job_id) -Travis.RepoIndexRoute = Ember.Route.extend Travis.SetupLastBuild, +Travis.RepoIndexRoute = Travis.Route.extend Travis.SetupLastBuild, setupController: (controller, model) -> @_super.apply this, arguments @controllerFor('repo').activate('current') renderTemplate: -> - @render 'build', outlet: 'pane', into: 'repo' + @render 'build', into: 'repo', outlet: 'pane' -Travis.RepoRoute = Ember.Route.extend +Travis.RepoRoute = Travis.Route.extend renderTemplate: -> @render 'repo' @@ -253,15 +258,20 @@ Travis.RepoRoute = Ember.Route.extend model: (params) -> slug = "#{params.owner}/#{params.name}" - Travis.Repo.fetchBySlug(slug) actions: - error: -> - Ember.run.next this, -> - @render('repos/not_found', outlet: 'main') + error: (error) -> + # if error throwed has a slug (ie. it was probably repo not found) + # set the slug on index.error controller to allow to properly + # display the repo information + if error.slug + this.controllerFor('index.error').set('slug', error.slug) -Travis.IndexRoute = Ember.Route.extend + # bubble to the top + return true + +Travis.IndexRoute = Travis.Route.extend renderTemplate: -> $('body').attr('id', 'home') @@ -273,11 +283,7 @@ Travis.IndexRoute = Ember.Route.extend @container.lookup('controller:repos').activate() @container.lookup('controller:application').connectLayout 'home' -Travis.IndexLoadingRoute = Ember.Route.extend - renderTemplate: -> - @render('index_loading') - -Travis.StatsRoute = Ember.Route.extend +Travis.StatsRoute = Travis.Route.extend renderTemplate: -> $('body').attr('id', 'stats') @@ -287,7 +293,7 @@ Travis.StatsRoute = Ember.Route.extend setupController: -> @container.lookup('controller:application').connectLayout('simple') -Travis.NotFoundRoute = Ember.Route.extend +Travis.NotFoundRoute = Travis.Route.extend renderTemplate: -> $('body').attr('id', 'not-found') @@ -297,7 +303,7 @@ Travis.NotFoundRoute = Ember.Route.extend setupController: -> @container.lookup('controller:application').connectLayout('simple') -Travis.ProfileRoute = Ember.Route.extend +Travis.ProfileRoute = Travis.Route.extend needsAuth: true setupController: -> @@ -310,16 +316,16 @@ Travis.ProfileRoute = Ember.Route.extend @render 'top', outlet: 'top' @render 'accounts', outlet: 'left' @render 'flash', outlet: 'flash' - @render 'profile' + @_super.apply(this, arguments) -Travis.ProfileIndexRoute = Ember.Route.extend +Travis.ProfileIndexRoute = Travis.Route.extend setupController: -> @container.lookup('controller:profile').activate 'hooks' renderTemplate: -> @render 'hooks', outlet: 'pane', into: 'profile', controller: 'profile' -Travis.AccountRoute = Ember.Route.extend +Travis.AccountRoute = Travis.Route.extend setupController: (controller, account) -> profileController = @container.lookup('controller:profile') profileController.activate 'hooks' @@ -352,21 +358,21 @@ Travis.AccountRoute = Ember.Route.extend else {} -Travis.AccountIndexRoute = Ember.Route.extend +Travis.AccountIndexRoute = Travis.Route.extend setupController: -> @container.lookup('controller:profile').activate 'hooks' renderTemplate: -> @render 'hooks', outlet: 'pane', into: 'profile' -Travis.AccountProfileRoute = Ember.Route.extend +Travis.AccountProfileRoute = Travis.Route.extend setupController: -> @container.lookup('controller:profile').activate 'user' renderTemplate: -> @render 'user', outlet: 'pane', into: 'profile' -Travis.AuthRoute = Ember.Route.extend +Travis.AuthRoute = Travis.Route.extend renderTemplate: -> $('body').attr('id', 'auth') @@ -378,3 +384,25 @@ Travis.AuthRoute = Ember.Route.extend deactivate: -> @controllerFor('auth').set('redirected', false) + +Travis.RepoSettingsRoute = Travis.Route.extend + setupController: (controller, model) -> + # TODO: if repo is just a data hash with id and slug load it + # as incomplete record + model = Travis.Repo.find(model.id) if model && !model.get + @_super(controller, model) + + serialize: (repo) -> + slug = if repo.get then repo.get('slug') else repo.slug + [owner, name] = slug.split('/') + { owner: owner, name: name } + + model: (params) -> + slug = "#{params.owner}/#{params.name}" + Travis.Repo.fetchBySlug(slug) + + afterModel: (repo) -> + # I'm using afterModel to fetch settings, because model is not always called. + # If link-to already provides a model, it will be just set as a route context. + repo.fetchSettings().then (settings) -> + repo.set('settings', settings) diff --git a/assets/scripts/app/templates/components/travis-switch.hbs b/assets/scripts/app/templates/components/travis-switch.hbs index e7b20837..18617602 100644 --- a/assets/scripts/app/templates/components/travis-switch.hbs +++ b/assets/scripts/app/templates/components/travis-switch.hbs @@ -1,4 +1,4 @@ -{{#if active}} +{{#if _active}} ON {{else}} OFF diff --git a/assets/scripts/app/templates/index_loading.hbs b/assets/scripts/app/templates/index_loading.hbs deleted file mode 100644 index 0277cf2e..00000000 --- a/assets/scripts/app/templates/index_loading.hbs +++ /dev/null @@ -1 +0,0 @@ -
Loading
diff --git a/assets/scripts/app/templates/profile/tabs/hooks.hbs b/assets/scripts/app/templates/profile/tabs/hooks.hbs index a937db01..8be19160 100644 --- a/assets/scripts/app/templates/profile/tabs/hooks.hbs +++ b/assets/scripts/app/templates/profile/tabs/hooks.hbs @@ -23,7 +23,7 @@

{{hook.description}}

- + {{#link-to "repo.settings" hook.repo class="repo-settings-icon tool-tip" title="Repository settings"}}{{/link-to}} {{travis-switch action="toggle" target=hook}}
diff --git a/assets/scripts/app/templates/repos/not_found.hbs b/assets/scripts/app/templates/repos/not_found.hbs deleted file mode 100644 index 57d6f053..00000000 --- a/assets/scripts/app/templates/repos/not_found.hbs +++ /dev/null @@ -1,3 +0,0 @@ -
- The repository at {{slug}} was not found. -
diff --git a/assets/scripts/app/templates/repos/show.hbs b/assets/scripts/app/templates/repos/show.hbs index c1bf53b9..9b80786a 100644 --- a/assets/scripts/app/templates/repos/show.hbs +++ b/assets/scripts/app/templates/repos/show.hbs @@ -24,4 +24,3 @@ {{/if}} {{/if}} - diff --git a/assets/scripts/app/templates/repos/show/tools.hbs b/assets/scripts/app/templates/repos/show/tools.hbs index 5fc4135e..65f865b7 100644 --- a/assets/scripts/app/templates/repos/show/tools.hbs +++ b/assets/scripts/app/templates/repos/show/tools.hbs @@ -11,6 +11,12 @@ {{/if}} + {{#if view.displaySettingsLink}} +
  • + {{#linkTo "repo.settings" view.repo}}Settings{{/linkTo}} +
  • + {{/if}} + diff --git a/assets/scripts/app/views.coffee b/assets/scripts/app/views.coffee index c03a0b65..4fa13d04 100644 --- a/assets/scripts/app/views.coffee +++ b/assets/scripts/app/views.coffee @@ -45,6 +45,7 @@ Travis.FirstSyncView = Travis.View.extend ) , Travis.config.syncingPageRedirectionTime + require 'views/accounts' require 'views/annotation' require 'views/application' diff --git a/assets/scripts/app/views/repo/show.coffee b/assets/scripts/app/views/repo/show.coffee index 0adaf3d9..bab9fd3b 100644 --- a/assets/scripts/app/views/repo/show.coffee +++ b/assets/scripts/app/views/repo/show.coffee @@ -115,6 +115,11 @@ Travis.reopen permissions.contains parseInt(@get('repo.id')) ).property('currentUser.permissions.length', 'repo.id') + hasPushPermission: (-> + if permissions = @get('currentUser.pushPermissions') + permissions.contains parseInt(@get('repo.id')) + ).property('currentUser.pushPermissions.length', 'repo.id') + hasAdminPermission: (-> if permissions = @get('currentUser.adminPermissions') permissions.contains parseInt(@get('repo.id')) @@ -124,6 +129,14 @@ Travis.reopen Travis.Urls.statusImage(@get('slug')) ).property('slug') + displaySettingsLink: (-> + @get('hasPushPermission') + ).property('hasPushPermission') + + displayStatusImages: (-> + @get('hasPermission') + ).property('hasPermission') + statusImages: -> @popupCloseAll() view = Travis.StatusImagesView.create(toolsView: this) diff --git a/assets/scripts/lib/travis/ajax.coffee b/assets/scripts/lib/travis/ajax.coffee index 00c32f01..fcd82eed 100644 --- a/assets/scripts/lib/travis/ajax.coffee +++ b/assets/scripts/lib/travis/ajax.coffee @@ -23,13 +23,14 @@ Travis.ajax = Em.Object.create !result ajax: (url, method, options) -> + method = method || "GET" method = method.toUpperCase() endpoint = Travis.config.api_endpoint || '' options = options || {} token = Travis.sessionStorage.getItem('travis.token') - if token && Travis.ajax.needsAuth(method, url) + if token && (Travis.ajax.needsAuth(method, url) || options.forceAuth) options.headers ||= {} options.headers['Authorization'] ||= "token #{token}" diff --git a/assets/scripts/spec/integration/routes_spec.coffee b/assets/scripts/spec/integration/routes_spec.coffee index bf491c1c..1cfe3fe8 100644 --- a/assets/scripts/spec/integration/routes_spec.coffee +++ b/assets/scripts/spec/integration/routes_spec.coffee @@ -1,9 +1,13 @@ -#module "Router", -# setup: -> -# Ember.run -> Travis.advanceReadiness() -# teardown: -> -# Ember.run -> Travis.reset() -# -#test 'renders notFound template when URL can\t be found', -> -# visit('/somehing/something/something/.../dark/side/..../something/something/something/.../complete').then -> -# equal('The requested page was not found.', $('#main').text().trim()) +module "Router", + setup: -> + Ember.run -> Travis.advanceReadiness() + teardown: -> + Ember.run -> Travis.reset() + +test 'renders notFound template when URL can\t be found', -> + visit('/somehing/something/something/.../dark/side/..../something/something/something/.../complete').then -> + equal($('#main').text().trim(), 'The requested page was not found.') + +test 'renders repo not found information when repo can\'t be found', -> + visit('/what-is-this/i-dont-even').then -> + equal($('#main').text().trim(), 'The repository at what-is-this/i-dont-even was not found.') diff --git a/assets/scripts/spec/support/mocks.coffee b/assets/scripts/spec/support/mocks.coffee index e4786764..d4e7b377 100644 --- a/assets/scripts/spec/support/mocks.coffee +++ b/assets/scripts/spec/support/mocks.coffee @@ -77,7 +77,8 @@ $.mockjax if !settings.data this.responseText = { repos: repos } else if slug = settings.data.slug - this.responseText = { repos: [$.detect(repos, (repository) -> repository.slug == slug)] } + reposForResponse = $.select(repos, (repository) -> repository.slug == slug) + this.responseText = { repos: reposForResponse } else if search = settings.data.search this.responseText = { repos: $.select(repos, (repository) -> repository.slug.indexOf(search) > -1).toArray() } else if settings.data.member diff --git a/assets/styles/app/loading.sass b/assets/styles/app/loading.sass index 8278162e..2f2a2584 100644 --- a/assets/styles/app/loading.sass +++ b/assets/styles/app/loading.sass @@ -11,7 +11,7 @@ .loading display: none -span.loading +span.loading, span.saving padding: 0 25px 0 0 font-size: $font-size-small color: $color-text-lighter diff --git a/assets/styles/components/travis-switch.sass b/assets/styles/components/travis-switch.sass index 342aaac6..5b7ea12e 100644 --- a/assets/styles/components/travis-switch.sass +++ b/assets/styles/components/travis-switch.sass @@ -1,6 +1,10 @@ +.settings-row + margin-top: 20px + .travis-switch position: relative - display: block + display: inline-block + float: left width: 60px height: 18px margin: 0 10px 0 15px diff --git a/assets/styles/profile/hooks.sass b/assets/styles/profile/hooks.sass index cc639438..2411c8ee 100644 --- a/assets/styles/profile/hooks.sass +++ b/assets/styles/profile/hooks.sass @@ -57,14 +57,14 @@ float: left display: block - .github-admin + .repo-settings-icon // Overriding an earlier definition above, which is probably // obsolete. TODO: Remove if so. position: relative height: 20px width: 20px padding-right: 0 - background: inline-image('ui/github-admin.png') no-repeat 3px 4px + background: inline-image('ui/repo-settings.png') no-repeat 3px 4px &:hover > a