diff --git a/app/components/jobs-item.coffee b/app/components/jobs-item.coffee index d2a60524..eb87dcfc 100644 --- a/app/components/jobs-item.coffee +++ b/app/components/jobs-item.coffee @@ -7,6 +7,15 @@ JobsItemComponent = Ember.Component.extend classNameBindings: ['job.state'] classNames: ['tile', 'tile--jobs', 'row'] + isAnimating: (-> + state = @get('job.state') + animationStates = ['received', 'queued', 'started', 'booting'] + + unless animationStates.indexOf(state) == -1 + true + + ).property('job.state') + languages: (-> output = [] diff --git a/app/routes/settings.coffee b/app/routes/settings.coffee index 33d63f16..76889e85 100644 --- a/app/routes/settings.coffee +++ b/app/routes/settings.coffee @@ -42,12 +42,31 @@ Route = TravisRoute.extend response.active ); + hasPushAccess: -> + repoId = parseInt @modelFor('repo').get('id') + pushAccess = true + + Ajax.get '/users/permissions', (data) => + + admin = data.admin.filter (item) -> + return item == repoId + push = data.push.filter (item) -> + return item == repoId + pull = data.pull.filter (item) -> + return item == repoId + + if Ember.isEmpty admin && Ember.isEmpty push && !Ember.isEmpty pull + pushAccess = false + + pushAccess + model: () -> return Ember.RSVP.hash({ settings: @modelFor('repo').fetchSettings(), envVars: this.fetchEnvVars(), sshKey: this.fetchSshKey(), customSshKey: this.fetchCustomSshKey(), + hasPushAccess: this.hasPushAccess(), repositoryActive: this.fetchRepositoryActiveFlag() }); diff --git a/app/styles/app/layouts/build-job.sass b/app/styles/app/layouts/build-job.sass index 3e8c6886..615196af 100644 --- a/app/styles/app/layouts/build-job.sass +++ b/app/styles/app/layouts/build-job.sass @@ -38,6 +38,9 @@ .tile-status--job width: 2em + .svg-booting + margin: 0.7em 0.3em + .jobs-item padding: .1em 0 .icon diff --git a/app/styles/app/layouts/requests.sass b/app/styles/app/layouts/requests.sass index 74108110..ac331376 100644 --- a/app/styles/app/layouts/requests.sass +++ b/app/styles/app/layouts/requests.sass @@ -34,7 +34,7 @@ .requests-time @media #{$medium-up} padding-left: 2em - border-left: 1px solid $grey-lighter + border-left: 1px solid $cream-dark .tile--jobs padding-left: 2.5em diff --git a/app/styles/app/modules/icons.sass b/app/styles/app/modules/icons.sass index 03c63cb3..6a43244a 100644 --- a/app/styles/app/modules/icons.sass +++ b/app/styles/app/modules/icons.sass @@ -121,22 +121,19 @@ .icon--env background-image: inline-image('svg/icon-environment-dark2.svg') -.icon--cross-red, .icon--job.failed, .icon--job.rejected background-image: inline-image('svg/icon-job-failed.svg') -.icon--check-green, .icon--job.passed, .icon--job.accepted background-image: inline-image('svg/icon-job-passed.svg') -.icon--error-grey, .icon--job.errored background-image: inline-image('svg/icon-job-errored.svg') .icon--job.started, -.icon--job.created, -.icon--job.received, .icon--job.queued, -.icon--started-yellow +.icon--job.booting, +.icon--job.received, +.icon--job.created, background-image: inline-image('svg/icon-job-started.svg') .icon--job.canceled background-image: inline-image('svg/icon-job-canceled.svg') @@ -210,3 +207,29 @@ .icon-flag background-image: inline-image('svg/notice-flag.svg') + + +.icon-receiving + margin: 0.3rem 0.5rem; + display: inline-block; + i + width: 4px + height: 4px + border-radius: 50% + display: inline-block + background-color: $start-bg-color + transform-origin: center center + animation: bubbleScale 1.2s infinite linear + i:nth-of-type(2) + animation-delay: 0.35s + i:nth-of-type(3) + animation-delay: 0.7s + + +@keyframes bubbleScale + 0%, 80%, 100% + transform: scale(0) + + 40% + transform: scale(1.0) + diff --git a/app/styles/app/modules/tooltips.sass b/app/styles/app/modules/tooltips.sass index 4c6d783f..7a8625dc 100644 --- a/app/styles/app/modules/tooltips.sass +++ b/app/styles/app/modules/tooltips.sass @@ -1,8 +1,4 @@ %tooltip - &:hover .tooltip-bubble - transform: translateY(0) - opacity: 1 - .tooltip-bubble position: absolute top: -2.8em @@ -18,6 +14,7 @@ line-height: 1.3 text-align: center white-space: nowrap + visibility: hidden transition: all 100ms ease transform: translateY(20%) @@ -27,7 +24,6 @@ color: $white &:hover text-decoration: underline - &:before content: "" position: absolute @@ -38,6 +34,11 @@ z-index: -1 background-color: #818383 + &:hover .tooltip-bubble + transform: translateY(0) + opacity: 1 + visibility: visible + .tooltip @extend %tooltip .tooltip-bubble diff --git a/app/styles/app/userlike.sass b/app/styles/app/userlike.sass index 20622ffd..657c5b87 100644 --- a/app/styles/app/userlike.sass +++ b/app/styles/app/userlike.sass @@ -2,7 +2,7 @@ .feedback-button display: none position: fixed - right: 4% + right: 9% left: auto bottom: 0 margin: 0 @@ -17,6 +17,9 @@ color: #399399 z-index: 89 + @media #{$medium-up} + right: 5% + .feedback-button:hover transform: translateY(5%) diff --git a/app/templates/components/jobs-item.hbs b/app/templates/components/jobs-item.hbs index 093678bd..701c8d09 100644 --- a/app/templates/components/jobs-item.hbs +++ b/app/templates/components/jobs-item.hbs @@ -1,6 +1,10 @@ {{#link-to "job" repo job}}
- + {{#if isAnimating}} + + {{else}} + + {{/if}}

diff --git a/app/templates/components/ssh-key.hbs b/app/templates/components/ssh-key.hbs index 91b8cadf..6120f9aa 100644 --- a/app/templates/components/ssh-key.hbs +++ b/app/templates/components/ssh-key.hbs @@ -11,12 +11,19 @@ {{#if isDeleting}} {{loading-indicator}} {{else}} -

- - - -
Delete
-
+ {{#if pushAccess}} +
+ + + +
Delete
+
+ {{else}} +
+ +
You can't
delete keys
+
+ {{/if}} {{/if}} {{else}} diff --git a/app/templates/settings.hbs b/app/templates/settings.hbs index 0fdaecb0..60e25c6d 100644 --- a/app/templates/settings.hbs +++ b/app/templates/settings.hbs @@ -30,12 +30,19 @@

SSH Key

{{#if model.customSshKey}} - {{ssh-key key=model.customSshKey sshKeyDeleted="sshKeyDeleted"}} + {{ssh-key key=model.customSshKey sshKeyDeleted="sshKeyDeleted" pushAccess=model.hasPushAccess}} {{else}} {{ssh-key key=model.sshKey}} - {{add-ssh-key repo=repo sshKeyAdded="sshKeyAdded"}} + + {{#if model.hasPushAccess}} + {{add-ssh-key repo=repo sshKeyAdded="sshKeyAdded"}} + {{/if}} {{/if}} + {{#unless model.hasPushAccess}} +

You don't have sufficient permissons to add or remove ssh keys on this repository.

+ {{/unless}} + {{/if}} {{!--
diff --git a/tests/integration/components/ssh-key-test.js b/tests/integration/components/ssh-key-test.js index 0844f31b..ebdf5390 100644 --- a/tests/integration/components/ssh-key-test.js +++ b/tests/integration/components/ssh-key-test.js @@ -41,7 +41,7 @@ test('it renders the custom ssh key if custom key is set', function(assert) { }); -test('it deletes a custom key', function(assert) { +test('it deletes a custom key if permissions are right', function(assert) { assert.expect(1); var store = this.container.lookup('store:main'); @@ -52,7 +52,7 @@ test('it deletes a custom key', function(assert) { }); this.set('key', key); - this.render(hbs`{{ssh-key key=key sshKeyDeleted="sshKeyDeleted"}}`); + this.render(hbs`{{ssh-key key=key sshKeyDeleted="sshKeyDeleted" pushAccess=true}}`); this.on('sshKeyDeleted', function() {}); this.$('.ssh-key-action a').click(); @@ -60,3 +60,20 @@ test('it deletes a custom key', function(assert) { assert.ok(key.get('isDeleted'), 'key should be deleted'); }); + +test('it does not delete the custom key if permissions are insufficient', function(assert) { + assert.expect(1); + + var store = this.container.lookup('store:main'); + + var key; + Ember.run(function() { + key = store.push('sshKey', {description: 'fookey', fingerprint: 'somethingthing', id: 1}); + }); + + this.set('key', key); + this.render(hbs`{{ssh-key key=key sshKeyDeleted="sshKeyDeleted" pushAccess=false}}`); + + assert.ok(Ember.isEmpty(this.$('.ssh-key-action').find('a')), 'delete link should not be displayed'); + +}); \ No newline at end of file