Compare commits
4 Commits
master
...
chrome-for
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3477deb627 | ||
![]() |
21e40e7451 | ||
![]() |
daed6a6d8a | ||
![]() |
4e283993c6 |
11
.jshintrc
11
.jshintrc
|
@ -1,19 +1,10 @@
|
|||
{
|
||||
"predef": [
|
||||
"server",
|
||||
"document",
|
||||
"window",
|
||||
"-Promise",
|
||||
"jQuery",
|
||||
"Visibility",
|
||||
"$",
|
||||
"Travis",
|
||||
"_cio",
|
||||
"_gaq",
|
||||
"Log",
|
||||
"moment",
|
||||
"Pusher",
|
||||
"md5"
|
||||
"Visibility"
|
||||
],
|
||||
"browser": true,
|
||||
"boss": true,
|
||||
|
|
17
.travis.yml
17
.travis.yml
|
@ -18,8 +18,14 @@ matrix:
|
|||
|
||||
addons:
|
||||
sauce_connect: true
|
||||
apt:
|
||||
sources:
|
||||
- google-chrome
|
||||
packages:
|
||||
- google-chrome-stable
|
||||
|
||||
sudo: false
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
cache:
|
||||
branch: md5deep
|
||||
|
@ -29,16 +35,17 @@ cache:
|
|||
before_install:
|
||||
- "npm config set spin false"
|
||||
- "npm install -g npm@^2"
|
||||
- mkdir travis-phantomjs
|
||||
- wget https://s3.amazonaws.com/travis-phantomjs/phantomjs-2.0.0-ubuntu-12.04.tar.bz2 -O $PWD/travis-phantomjs/phantomjs-2.0.0-ubuntu-12.04.tar.bz2
|
||||
- tar -xvf $PWD/travis-phantomjs/phantomjs-2.0.0-ubuntu-12.04.tar.bz2 -C $PWD/travis-phantomjs
|
||||
- export PATH=$PWD/travis-phantomjs:$PATH
|
||||
- "export DISPLAY=:99.0"
|
||||
- "sh -e /etc/init.d/xvfb start"
|
||||
|
||||
install:
|
||||
- npm install -g bower
|
||||
- npm install
|
||||
- bower install
|
||||
|
||||
before_script:
|
||||
- ruby ci/prepare_testem.rb
|
||||
|
||||
script:
|
||||
- ember try $EMBER_VERSION
|
||||
|
||||
|
|
|
@ -65,6 +65,3 @@ DEPENDENCIES
|
|||
sinatra
|
||||
sinatra-contrib
|
||||
travis-web!
|
||||
|
||||
BUNDLED WITH
|
||||
1.10.1
|
||||
|
|
33
README.md
33
README.md
|
@ -18,37 +18,6 @@ And open http://localhost:4200 in the browser.
|
|||
|
||||
Alternatively you can run `ember build --watch` and start the server with `waiter/script/server`
|
||||
|
||||
### Running the app in private repos mode
|
||||
|
||||
At the moment Travis CI is available as two separate sites - https://travis-ci.org for Open Source
|
||||
projects and https://travis-ci.com for private projects. travis-web will connect
|
||||
to the Open Source version by default. In order to connect it to the API for private projects
|
||||
you need to run:
|
||||
|
||||
```
|
||||
TRAVIS_PRO=true ember serve --ssl --ssl-key=ssl/server.key --ssl-cert=ssl/server.crt
|
||||
```
|
||||
|
||||
One caveat here is that the command will start server with SSL, so the page will
|
||||
be accessible at https://localhost:4200 (note `https` part).
|
||||
|
||||
### Running on SSL in general
|
||||
|
||||
Sometimes there is a need to test the app with an SSL connection. This is required
|
||||
to make Pusher work when running Travis CI Pro, but it may also be needed in other
|
||||
situations.
|
||||
|
||||
There's already an SSL certificate in the `ssl` directory, which is set for `localhost`
|
||||
host. If you want to use it, you can start the server with:
|
||||
|
||||
```
|
||||
ember serve --ssl --ssl-key=ssl/server.key --ssl-cert=ssl/server.crt
|
||||
```
|
||||
|
||||
In case you want your own certificate, you can follow the instructions posted
|
||||
here: https://gist.github.com/trcarden/3295935 and then point the server to your
|
||||
certificate with `--ssl-key` and `--ssl-cert`.
|
||||
|
||||
### Running tests
|
||||
|
||||
To run a test suite execute:
|
||||
|
@ -62,7 +31,7 @@ You can also start an interactive test runner for easier development:
|
|||
|
||||
### Updating the team page
|
||||
|
||||
The team information can be found in `app/routes/team.js`.
|
||||
The team information can be found in `app/routes/team.coffee`.
|
||||
To add another member just add the info in the same style as the previous ones. Like so
|
||||
|
||||
{
|
||||
|
|
9
SSL_LOCALLY.md
Normal file
9
SSL_LOCALLY.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
Sometimes there is a need to test the app with an SSL connection, for example for
|
||||
testing pusher on Travis CI Pro.
|
||||
|
||||
In order to run the app with SSL enabled you need to:
|
||||
|
||||
* generate self signed certificate as described here: https://gist.github.com/trcarden/3295935
|
||||
* one difference is that you need to use localhost.ssl, because travis-api
|
||||
doesn't whitelist localhost.ssl at the moment
|
||||
* run Ember app with ssl options: `TRAVIS_PRO=true ember serve --ssl --ssl-key=ssl/server.key --ssl-cert=ssl/server.crt`
|
30
app/adapters/application.coffee
Normal file
30
app/adapters/application.coffee
Normal file
|
@ -0,0 +1,30 @@
|
|||
`import DS from 'ember-data'`
|
||||
`import config from 'travis/config/environment'`
|
||||
|
||||
Adapter = DS.ActiveModelAdapter.extend
|
||||
auth: Ember.inject.service()
|
||||
|
||||
host: config.apiEndpoint
|
||||
coalesceFindRequests: true
|
||||
|
||||
ajaxOptions: (url, type, options) ->
|
||||
hash = @_super(url, type, options)
|
||||
|
||||
hash.headers ||= {}
|
||||
|
||||
hash.headers['accept'] = 'application/json; version=2'
|
||||
|
||||
if token = @get('auth').token()
|
||||
hash.headers['Authorization'] ||= "token #{token}"
|
||||
|
||||
hash
|
||||
|
||||
findMany: (store, type, ids) ->
|
||||
@ajax(@buildURL(type.modelName), 'GET', data: { ids: ids })
|
||||
|
||||
handleResponse: (status, headers, payload) ->
|
||||
if status > 299
|
||||
console.log "[ERROR] API responded with an error (#{status}): #{JSON.stringify(payload)}"
|
||||
return @_super.apply(this, arguments)
|
||||
|
||||
`export default Adapter`
|
|
@ -1,57 +0,0 @@
|
|||
import config from 'travis/config/environment';
|
||||
import Ember from 'ember';
|
||||
import ActiveModelAdapter from 'active-model-adapter';
|
||||
|
||||
export default ActiveModelAdapter.extend({
|
||||
auth: Ember.inject.service(),
|
||||
host: config.apiEndpoint,
|
||||
coalesceFindRequests: true,
|
||||
|
||||
// Before Ember Data 2.0 the default behaviour of running `findAll` was to get
|
||||
// new records only when there're no records in the store. This will change
|
||||
// to a different strategy in 2.0: when you run `findAll` it will not get any
|
||||
// new data initially, but it will try loading new data in the background.
|
||||
//
|
||||
// I'm disabling the new behaviour for now.
|
||||
shouldBackgroundReloadRecord() {
|
||||
return false;
|
||||
},
|
||||
|
||||
ajaxOptions(url, type, options) {
|
||||
var base, hash, token;
|
||||
|
||||
hash = this._super(...arguments);
|
||||
hash.headers = hash.headers || {};
|
||||
hash.headers['accept'] = 'application/json; version=2';
|
||||
|
||||
if (token = this.get('auth').token()) {
|
||||
if(!hash.headers['Authorization']) {
|
||||
hash.headers['Authorization'] = "token " + token;
|
||||
}
|
||||
}
|
||||
|
||||
return hash;
|
||||
},
|
||||
|
||||
findMany(store, type, ids) {
|
||||
return this.ajax(this.buildURL(type.modelName), 'GET', {
|
||||
data: {
|
||||
ids: ids
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
handleResponse(status, headers, payload) {
|
||||
if (status > 299) {
|
||||
console.log("[ERROR] API responded with an error (" + status + "): " + (JSON.stringify(payload)));
|
||||
}
|
||||
|
||||
return this._super(...arguments);
|
||||
},
|
||||
|
||||
// this can be removed once this PR is merged and live:
|
||||
// https://github.com/emberjs/data/pull/4204
|
||||
findRecord(store, type, id, snapshot) {
|
||||
return this.ajax(this.buildURL(type.modelName, id, snapshot, 'findRecord'), 'GET');
|
||||
}
|
||||
});
|
26
app/adapters/env-var.coffee
Normal file
26
app/adapters/env-var.coffee
Normal file
|
@ -0,0 +1,26 @@
|
|||
`import Ember from 'ember'`
|
||||
`import ApplicationAdapter from 'travis/adapters/application'`
|
||||
|
||||
Adapter = ApplicationAdapter.extend
|
||||
namespace: 'settings'
|
||||
|
||||
buildURL: (type, id, record) ->
|
||||
url = @_super.apply this, arguments
|
||||
|
||||
if record && (repoId = Ember.get(record, 'repo.id'))
|
||||
delimiter = if url.indexOf('?') != -1 then '&' else '?'
|
||||
url = "#{url}#{delimiter}repository_id=#{repoId}"
|
||||
|
||||
url
|
||||
|
||||
updateRecord: (store, type, record) ->
|
||||
data = {};
|
||||
serializer = store.serializerFor(type.typeKey);
|
||||
|
||||
serializer.serializeIntoHash(data, type, record);
|
||||
|
||||
id = Ember.get(record, 'id');
|
||||
|
||||
this.ajax(this.buildURL(type.typeKey, id, record), "PATCH", { data: data })
|
||||
|
||||
`export default Adapter`
|
|
@ -1,27 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import ApplicationAdapter from 'travis/adapters/application';
|
||||
|
||||
export default ApplicationAdapter.extend({
|
||||
namespace: 'settings',
|
||||
|
||||
buildURL(type, id, record) {
|
||||
var delimiter, repoId, url;
|
||||
url = this._super.apply(this, arguments);
|
||||
if (record && record.belongsTo('repo') && (repoId = record.belongsTo('repo').id)) {
|
||||
delimiter = url.indexOf('?') !== -1 ? '&' : '?';
|
||||
url = "" + url + delimiter + "repository_id=" + repoId;
|
||||
}
|
||||
return url;
|
||||
},
|
||||
|
||||
updateRecord(store, type, record) {
|
||||
var data, serializer;
|
||||
data = {};
|
||||
serializer = store.serializerFor(type.modelName);
|
||||
serializer.serializeIntoHash(data, type, record);
|
||||
var id = record.id;
|
||||
return this.ajax(this.buildURL(type.modelName, id, record), "PATCH", {
|
||||
data: data
|
||||
});
|
||||
}
|
||||
});
|
24
app/adapters/ssh-key.coffee
Normal file
24
app/adapters/ssh-key.coffee
Normal file
|
@ -0,0 +1,24 @@
|
|||
`import Ember from 'ember'`
|
||||
`import ApplicationAdapter from 'travis/adapters/application'`
|
||||
|
||||
Adapter = ApplicationAdapter.extend
|
||||
namespace: 'settings'
|
||||
|
||||
find: (store, type, id, record) ->
|
||||
@ajax(this.urlPrefix() + '/ssh_key/' + id, 'GET')
|
||||
|
||||
deleteRecord: (store, type, record) ->
|
||||
id = Ember.get(record, 'id')
|
||||
|
||||
@ajax(this.urlPrefix() + '/ssh_key/' + id, "DELETE");
|
||||
|
||||
createRecord: (store, type, record) ->
|
||||
data = {};
|
||||
serializer = store.serializerFor(type.typeKey);
|
||||
serializer.serializeIntoHash(data, type, record, { includeId: true });
|
||||
|
||||
id = Ember.get(record, 'id')
|
||||
|
||||
this.ajax(this.urlPrefix() + '/ssh_key/' + id, "PATCH", { data: data })
|
||||
|
||||
`export default Adapter`
|
|
@ -1,29 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import ApplicationAdapter from 'travis/adapters/application';
|
||||
|
||||
export default ApplicationAdapter.extend({
|
||||
namespace: 'settings',
|
||||
|
||||
findRecord(store, type, id, record) {
|
||||
return this.ajax(this.urlPrefix() + '/ssh_key/' + id, 'GET');
|
||||
},
|
||||
|
||||
deleteRecord(store, type, record) {
|
||||
var id = record.id;
|
||||
return this.ajax(this.urlPrefix() + '/ssh_key/' + id, "DELETE");
|
||||
},
|
||||
|
||||
createRecord(store, type, record) {
|
||||
var data, serializer;
|
||||
data = {};
|
||||
serializer = store.serializerFor(type.modelName);
|
||||
serializer.serializeIntoHash(data, type, record, {
|
||||
includeId: true
|
||||
});
|
||||
|
||||
var id = record.id;
|
||||
return this.ajax(this.urlPrefix() + '/ssh_key/' + id, "PATCH", {
|
||||
data: data
|
||||
});
|
||||
}
|
||||
});
|
|
@ -1,8 +1,8 @@
|
|||
import Ember from 'ember';
|
||||
import DS from 'ember-data';
|
||||
import config from 'travis/config/environment';
|
||||
import RESTAdapter from 'ember-data/adapters/rest';
|
||||
|
||||
export default RESTAdapter.extend({
|
||||
export default DS.RESTAdapter.extend({
|
||||
auth: Ember.inject.service(),
|
||||
host: config.apiEndpoint,
|
||||
|
||||
|
@ -54,11 +54,5 @@ export default RESTAdapter.extend({
|
|||
pathForType: function(modelName, id) {
|
||||
var underscored = Ember.String.underscore(modelName);
|
||||
return id ? underscored : Ember.String.pluralize(underscored);
|
||||
},
|
||||
|
||||
// this can be removed once this PR is merged and live:
|
||||
// https://github.com/emberjs/data/pull/4204
|
||||
findRecord(store, type, id, snapshot) {
|
||||
return this.ajax(this.buildURL(type.modelName, id, snapshot, 'findRecord'), 'GET');
|
||||
}
|
||||
});
|
||||
|
|
111
app/app.coffee
Normal file
111
app/app.coffee
Normal file
|
@ -0,0 +1,111 @@
|
|||
`import Ember from 'ember'`
|
||||
`import Resolver from 'ember/resolver'`
|
||||
`import loadInitializers from 'ember/load-initializers'`
|
||||
`import config from './config/environment'`
|
||||
|
||||
Ember.MODEL_FACTORY_INJECTIONS = true
|
||||
|
||||
Ember.LinkView.reopen(
|
||||
attributeBindings: ['alt']
|
||||
);
|
||||
|
||||
App = Ember.Application.extend(Ember.Evented,
|
||||
LOG_TRANSITIONS: true
|
||||
LOG_TRANSITIONS_INTERNAL: true
|
||||
LOG_ACTIVE_GENERATION: true
|
||||
LOG_MODULE_RESOLVER: true
|
||||
LOG_VIEW_LOOKUPS: true
|
||||
#LOG_RESOLVER: true
|
||||
|
||||
modulePrefix: config.modulePrefix
|
||||
podModulePrefix: config.podModulePrefix
|
||||
Resolver: Resolver
|
||||
|
||||
lookup: ->
|
||||
@__container__.lookup.apply @__container__, arguments
|
||||
|
||||
flash: (options) ->
|
||||
Travis.lookup('controller:flash').loadFlashes([options])
|
||||
|
||||
toggleSidebar: ->
|
||||
$('body').toggleClass('maximized')
|
||||
# TODO gotta force redraws here :/
|
||||
element = $('<span></span>')
|
||||
$('#top .profile').append(element)
|
||||
Em.run.later (-> element.remove()), 10
|
||||
element = $('<span></span>')
|
||||
$('#repo').append(element)
|
||||
Em.run.later (-> element.remove()), 10
|
||||
|
||||
ready: ->
|
||||
location.href = location.href.replace('#!/', '') if location.hash.slice(0, 2) == '#!'
|
||||
|
||||
@on 'user:signed_in', (user) ->
|
||||
Travis.onUserUpdate(user)
|
||||
|
||||
@on 'user:refreshed', (user) ->
|
||||
Travis.onUserUpdate(user)
|
||||
|
||||
@on 'user:synced', (user) ->
|
||||
Travis.onUserUpdate(user)
|
||||
|
||||
@on 'user:signed_out', () ->
|
||||
if config.userlike
|
||||
Travis.removeUserlike()
|
||||
|
||||
currentDate: ->
|
||||
new Date()
|
||||
|
||||
onUserUpdate: (user) ->
|
||||
if config.pro
|
||||
@identifyCustomer(user)
|
||||
if config.userlike
|
||||
@setupUserlike(user)
|
||||
|
||||
@subscribePusher(user)
|
||||
|
||||
subscribePusher: (user) ->
|
||||
return unless user.channels
|
||||
channels = user.channels
|
||||
if config.pro
|
||||
channels = channels.map (channel) ->
|
||||
if channel.match /^private-/
|
||||
channel
|
||||
else
|
||||
"private-#{channel}"
|
||||
|
||||
Travis.pusher.subscribeAll(channels)
|
||||
|
||||
setupUserlike: (user) ->
|
||||
|
||||
btn = document.getElementById('userlikeCustomTab')
|
||||
btn.classList.add("logged-in")
|
||||
|
||||
userlikeData = window.userlikeData = {}
|
||||
userlikeData.user = {}
|
||||
|
||||
userlikeData.user.name= user.login;
|
||||
userlikeData.user.email = user.email;
|
||||
|
||||
unless document.getElementById('userlike-script')
|
||||
s = document.createElement('script')
|
||||
s.id = 'userlike-script'
|
||||
s.src = '//userlike-cdn-widgets.s3-eu-west-1.amazonaws.com/0327dbb23382ccbbb91b445b76e8a91d4b37d90ef9f2faf84e11177847ff7bb9.js'
|
||||
document.body.appendChild(s)
|
||||
|
||||
removeUserlike: () ->
|
||||
btn = document.getElementById('userlikeCustomTab')
|
||||
btn.classList.remove("logged-in")
|
||||
|
||||
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
|
||||
)
|
||||
loadInitializers(App, config.modulePrefix)
|
||||
|
||||
`export default App`
|
130
app/app.js
130
app/app.js
|
@ -1,130 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import Resolver from './resolver';
|
||||
import loadInitializers from 'ember-load-initializers';
|
||||
import config from './config/environment';
|
||||
|
||||
Ember.MODEL_FACTORY_INJECTIONS = true;
|
||||
|
||||
Ember.LinkComponent.reopen({
|
||||
attributeBindings: ['alt']
|
||||
});
|
||||
|
||||
var App = Ember.Application.extend(Ember.Evented, {
|
||||
LOG_TRANSITIONS: true,
|
||||
LOG_TRANSITIONS_INTERNAL: true,
|
||||
LOG_ACTIVE_GENERATION: true,
|
||||
LOG_MODULE_RESOLVER: true,
|
||||
LOG_VIEW_LOOKUPS: true,
|
||||
modulePrefix: config.modulePrefix,
|
||||
podModulePrefix: config.podModulePrefix,
|
||||
Resolver: Resolver,
|
||||
|
||||
flash(options) {
|
||||
return Ember.getOwner(Travis).lookup('controller:flash').loadFlashes([options]);
|
||||
},
|
||||
|
||||
toggleSidebar() {
|
||||
var element;
|
||||
$('body').toggleClass('maximized');
|
||||
element = $('<span></span>');
|
||||
$('#top .profile').append(element);
|
||||
Ember.run.later((function() {
|
||||
return element.remove();
|
||||
}), 10);
|
||||
element = $('<span></span>');
|
||||
$('#repo').append(element);
|
||||
return Ember.run.later((function() {
|
||||
return element.remove();
|
||||
}), 10);
|
||||
},
|
||||
|
||||
ready() {
|
||||
if (location.hash.slice(0, 2) === '#!') {
|
||||
location.href = location.href.replace('#!/', '');
|
||||
}
|
||||
this.on('user:signed_in', function(user) {
|
||||
return Travis.onUserUpdate(user);
|
||||
});
|
||||
this.on('user:refreshed', function(user) {
|
||||
return Travis.onUserUpdate(user);
|
||||
});
|
||||
this.on('user:synced', function(user) {
|
||||
return Travis.onUserUpdate(user);
|
||||
});
|
||||
return this.on('user:signed_out', function() {
|
||||
if (config.userlike) {
|
||||
return Travis.removeUserlike();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
currentDate() {
|
||||
return new Date();
|
||||
},
|
||||
|
||||
onUserUpdate(user) {
|
||||
if (config.pro) {
|
||||
this.identifyCustomer(user);
|
||||
}
|
||||
if (config.userlike) {
|
||||
this.setupUserlike(user);
|
||||
}
|
||||
return this.subscribePusher(user);
|
||||
},
|
||||
|
||||
subscribePusher(user) {
|
||||
var channels;
|
||||
if (!user.channels) {
|
||||
return;
|
||||
}
|
||||
channels = user.channels;
|
||||
if (config.pro) {
|
||||
channels = channels.map(function(channel) {
|
||||
if (channel.match(/^private-/)) {
|
||||
return channel;
|
||||
} else {
|
||||
return "private-" + channel;
|
||||
}
|
||||
});
|
||||
}
|
||||
return Travis.pusher.subscribeAll(channels);
|
||||
},
|
||||
|
||||
setupUserlike(user) {
|
||||
var btn, s, userlikeData;
|
||||
btn = document.getElementById('userlikeCustomTab');
|
||||
btn.classList.add("logged-in");
|
||||
userlikeData = window.userlikeData = {};
|
||||
userlikeData.user = {};
|
||||
userlikeData.user.name = user.login;
|
||||
userlikeData.user.email = user.email;
|
||||
if (!document.getElementById('userlike-script')) {
|
||||
s = document.createElement('script');
|
||||
s.id = 'userlike-script';
|
||||
s.src = '//userlike-cdn-widgets.s3-eu-west-1.amazonaws.com/0327dbb23382ccbbb91b445b76e8a91d4b37d90ef9f2faf84e11177847ff7bb9.js';
|
||||
return document.body.appendChild(s);
|
||||
}
|
||||
},
|
||||
|
||||
removeUserlike() {
|
||||
var btn;
|
||||
btn = document.getElementById('userlikeCustomTab');
|
||||
return btn.classList.remove("logged-in");
|
||||
},
|
||||
|
||||
identifyCustomer(user) {
|
||||
if (_cio && _cio.identify) {
|
||||
return _cio.identify({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
created_at: (Date.parse(user.created_at) / 1000) || null,
|
||||
login: user.login
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
loadInitializers(App, config.modulePrefix);
|
||||
|
||||
export default App;
|
46
app/components/add-env-var.coffee
Normal file
46
app/components/add-env-var.coffee
Normal file
|
@ -0,0 +1,46 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
AddEnvVarComponent = Ember.Component.extend
|
||||
|
||||
classNames: ['form--envvar']
|
||||
classNameBindings: ['nameIsBlank:form-error']
|
||||
|
||||
store: Ember.inject.service()
|
||||
|
||||
isValid: () ->
|
||||
if Ember.isBlank(@get('name'))
|
||||
this.set('nameIsBlank', true)
|
||||
false
|
||||
else
|
||||
true
|
||||
|
||||
reset: ->
|
||||
@setProperties(name: null, value: null, public: null)
|
||||
|
||||
actions:
|
||||
save: ->
|
||||
return if @get('isSaving')
|
||||
@set('isSaving', true)
|
||||
|
||||
if @isValid()
|
||||
env_var = @get('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()
|
||||
, =>
|
||||
@set('isSaving', false)
|
||||
else
|
||||
@set('isSaving', false)
|
||||
|
||||
nameChanged: ->
|
||||
this.set('nameIsBlank', false)
|
||||
|
||||
|
||||
`export default AddEnvVarComponent`
|
|
@ -1,55 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['form--envvar'],
|
||||
classNameBindings: ['nameIsBlank:form-error'],
|
||||
store: Ember.inject.service(),
|
||||
|
||||
isValid() {
|
||||
if (Ember.isBlank(this.get('name'))) {
|
||||
this.set('nameIsBlank', true);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
reset() {
|
||||
return this.setProperties({
|
||||
name: null,
|
||||
value: null,
|
||||
"public": null
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
var env_var, self;
|
||||
if (this.get('isSaving')) {
|
||||
return;
|
||||
}
|
||||
this.set('isSaving', true);
|
||||
if (this.isValid()) {
|
||||
env_var = this.get('store').createRecord('env_var', {
|
||||
name: this.get('name'),
|
||||
value: this.get('value'),
|
||||
"public": this.get('public'),
|
||||
repo: this.get('repo')
|
||||
});
|
||||
self = this;
|
||||
return env_var.save().then(() => {
|
||||
this.set('isSaving', false);
|
||||
return this.reset();
|
||||
}, () => {
|
||||
return this.set('isSaving', false);
|
||||
});
|
||||
} else {
|
||||
return this.set('isSaving', false);
|
||||
}
|
||||
},
|
||||
|
||||
nameChanged() {
|
||||
return this.set('nameIsBlank', false);
|
||||
}
|
||||
}
|
||||
});
|
73
app/components/add-ssh-key.coffee
Normal file
73
app/components/add-ssh-key.coffee
Normal file
|
@ -0,0 +1,73 @@
|
|||
# `import Ember from 'ember'`
|
||||
|
||||
AddSshKeyComponent = Ember.Component.extend
|
||||
|
||||
classNames: ['form--sshkey']
|
||||
classNameBindings: ['valueError:form-error']
|
||||
|
||||
store: Ember.inject.service()
|
||||
isSaving: false
|
||||
|
||||
didInsertElement: () ->
|
||||
id = @get('repo.id')
|
||||
model = @get('store').recordForId('ssh_key', id)
|
||||
# TODO: this can be removed in favor of simply unloading record
|
||||
# once https://github.com/emberjs/data/pull/2867
|
||||
# and https://github.com/emberjs/data/pull/2870 are merged
|
||||
if model
|
||||
@get('store').dematerializeRecord(model._internalModel)
|
||||
typeMap = @get('store').typeMapFor(model.constructor)
|
||||
idToRecord = typeMap.idToRecord
|
||||
delete idToRecord[id]
|
||||
|
||||
model = @get('store').createRecord('ssh_key', id: id)
|
||||
@set('model', model)
|
||||
|
||||
isValid: () ->
|
||||
if Ember.isBlank(@get('value'))
|
||||
this.set('valueError', 'Value can\'t be blank.')
|
||||
false
|
||||
else
|
||||
true
|
||||
|
||||
reset: ->
|
||||
@setProperties(description: null, value: null)
|
||||
|
||||
valueChanged: (->
|
||||
this.set('valueError', false)
|
||||
).observes('value')
|
||||
|
||||
addErrorsFromResponse: (errArr) ->
|
||||
error = errArr[0].detail
|
||||
if error.code == 'not_a_private_key'
|
||||
this.set('valueError', 'This key is not a private key.')
|
||||
else if error.code == 'key_with_a_passphrase'
|
||||
this.set('valueError', 'The key can\'t have a passphrase.')
|
||||
|
||||
actions:
|
||||
|
||||
save: ->
|
||||
this.set('valueError', false)
|
||||
return if @get('isSaving')
|
||||
@set('isSaving', true)
|
||||
if @isValid()
|
||||
|
||||
ssh_key = @get('model').setProperties(
|
||||
description: @get('description')
|
||||
value: @get('value')
|
||||
)
|
||||
|
||||
ssh_key.save().then =>
|
||||
@set('isSaving', false)
|
||||
@reset()
|
||||
|
||||
@sendAction('sshKeyAdded', ssh_key)
|
||||
, (error) =>
|
||||
@set('isSaving', false)
|
||||
if error.errors
|
||||
@addErrorsFromResponse(error.errors)
|
||||
|
||||
else
|
||||
@set('isSaving', false)
|
||||
|
||||
`export default AddSshKeyComponent`
|
|
@ -1,85 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['form--sshkey'],
|
||||
classNameBindings: ['valueError:form-error'],
|
||||
store: Ember.inject.service(),
|
||||
isSaving: false,
|
||||
|
||||
didInsertElement() {
|
||||
var id = this.get('repo.id');
|
||||
var model = this.get('store').recordForId('ssh_key', id);
|
||||
|
||||
if (model) {
|
||||
this.get('store').unloadRecord(model);
|
||||
var typeMap = this.get('store').typeMapFor(model.constructor);
|
||||
var idToRecord = typeMap.idToRecord;
|
||||
delete idToRecord[id];
|
||||
}
|
||||
|
||||
model = this.get('store').createRecord('ssh_key', { id: id });
|
||||
|
||||
return this.set('model', model);
|
||||
},
|
||||
|
||||
isValid() {
|
||||
if (Ember.isBlank(this.get('value'))) {
|
||||
this.set('valueError', 'Value can\'t be blank.');
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
reset() {
|
||||
return this.setProperties({
|
||||
description: null,
|
||||
value: null
|
||||
});
|
||||
},
|
||||
|
||||
valueChanged: function() {
|
||||
return this.set('valueError', false);
|
||||
}.observes('value'),
|
||||
|
||||
addErrorsFromResponse(errArr) {
|
||||
var error = errArr[0].detail;
|
||||
|
||||
if (error.code === 'not_a_private_key') {
|
||||
return this.set('valueError', 'This key is not a private key.');
|
||||
} else if (error.code === 'key_with_a_passphrase') {
|
||||
return this.set('valueError', 'The key can\'t have a passphrase.');
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
var ssh_key;
|
||||
|
||||
this.set('valueError', false);
|
||||
if (this.get('isSaving')) {
|
||||
return;
|
||||
}
|
||||
this.set('isSaving', true);
|
||||
if (this.isValid()) {
|
||||
ssh_key = this.get('model');
|
||||
ssh_key.setProperties({
|
||||
description: this.get('description'),
|
||||
value: this.get('value')
|
||||
});
|
||||
return ssh_key.save().then(() => {
|
||||
this.set('isSaving', false);
|
||||
this.reset();
|
||||
return this.sendAction('sshKeyAdded', ssh_key);
|
||||
}, (error) => {
|
||||
this.set('isSaving', false);
|
||||
if (error.errors) {
|
||||
return this.addErrorsFromResponse(error.errors);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return this.set('isSaving', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
91
app/components/branch-row.coffee
Normal file
91
app/components/branch-row.coffee
Normal file
|
@ -0,0 +1,91 @@
|
|||
`import Ember from 'ember'`
|
||||
`import { gravatarImage } from 'travis/utils/urls'`
|
||||
`import { githubCommit as githubCommitUrl } from 'travis/utils/urls'`
|
||||
`import TravisRoute from 'travis/routes/basic'`
|
||||
`import config from 'travis/config/environment'`
|
||||
|
||||
BranchRowComponent = Ember.Component.extend
|
||||
routing: Ember.inject.service('-routing')
|
||||
tagName: 'li'
|
||||
classNameBindings: ['build.last_build.state']
|
||||
classNames: ['branch-row', 'row-li']
|
||||
isLoading: false
|
||||
isTriggering: false
|
||||
hasTriggered: false
|
||||
|
||||
urlGithubCommit: (->
|
||||
githubCommitUrl(@get('build.repository.slug'), @get('build.last_build.commit.sha'))
|
||||
).property('build.last_build')
|
||||
|
||||
getLast5Builds: (->
|
||||
|
||||
lastBuilds = Ember.ArrayProxy.create(
|
||||
content: [{}, {}, {}, {}, {}]
|
||||
isLoading: true,
|
||||
count: 0
|
||||
)
|
||||
|
||||
if !@get('build.last_build')
|
||||
lastBuilds.set('isLoading', false)
|
||||
else
|
||||
apiEndpoint = config.apiEndpoint
|
||||
repoId = @get('build.repository.id')
|
||||
branchName = @get('build.name')
|
||||
|
||||
options = {}
|
||||
if @get('auth.signedIn')
|
||||
options.headers = { Authorization: "token #{@auth.token()}" }
|
||||
|
||||
$.ajax("#{apiEndpoint}/v3/repo/#{repoId}/builds?branch.name=#{branchName}&limit=5&build.event_type=push,api", options).then (response) ->
|
||||
array = response.builds.map( (build) ->
|
||||
Ember.Object.create(build)
|
||||
)
|
||||
if array.length < 5
|
||||
for i in [1..5 - array.length] by 1
|
||||
array.push({})
|
||||
|
||||
lastBuilds.set('count', response['@pagination'].count)
|
||||
lastBuilds.set('content', array)
|
||||
lastBuilds.set('isLoading', false)
|
||||
|
||||
lastBuilds
|
||||
).property()
|
||||
|
||||
canTrigger: (->
|
||||
if !@get('auth.signedIn')
|
||||
false
|
||||
else
|
||||
permissions = @get('auth.currentUser.permissions')
|
||||
if permissions.contains parseInt(@get('build.repository.id'))
|
||||
true
|
||||
else
|
||||
false
|
||||
).property()
|
||||
|
||||
triggerBuild: (->
|
||||
apiEndpoint = config.apiEndpoint
|
||||
repoId = @get('build.repository.id')
|
||||
options = {
|
||||
type: 'POST',
|
||||
body: {
|
||||
request: {
|
||||
branch: @get('build.name')
|
||||
}
|
||||
}
|
||||
}
|
||||
if @get('auth.signedIn')
|
||||
options.headers = { Authorization: "token #{@auth.token()}" }
|
||||
$.ajax("#{apiEndpoint}/v3/repo/#{repoId}/requests", options).then (response) =>
|
||||
@set('isTriggering', false)
|
||||
@set('hasTriggered', true)
|
||||
)
|
||||
|
||||
actions:
|
||||
tiggerBuild: (branch) ->
|
||||
@set('isTriggering', true)
|
||||
@triggerBuild()
|
||||
|
||||
viewAllBuilds: (branch) ->
|
||||
@get('routing').transitionTo('builds')
|
||||
|
||||
`export default BranchRowComponent`
|
|
@ -1,103 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import { githubCommit as githubCommitUrl } from 'travis/utils/urls';
|
||||
import TravisRoute from 'travis/routes/basic';
|
||||
import config from 'travis/config/environment';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
routing: Ember.inject.service('-routing'),
|
||||
tagName: 'li',
|
||||
classNameBindings: ['build.last_build.state'],
|
||||
classNames: ['branch-row', 'row-li'],
|
||||
isLoading: false,
|
||||
isTriggering: false,
|
||||
hasTriggered: false,
|
||||
|
||||
urlGithubCommit: function() {
|
||||
return githubCommitUrl(this.get('build.repository.slug'), this.get('build.last_build.commit.sha'));
|
||||
}.property('build.last_build'),
|
||||
|
||||
getLast5Builds: function() {
|
||||
var apiEndpoint, branchName, lastBuilds, options, repoId;
|
||||
lastBuilds = Ember.ArrayProxy.create({
|
||||
content: [{}, {}, {}, {}, {}],
|
||||
isLoading: true,
|
||||
count: 0
|
||||
});
|
||||
if (!this.get('build.last_build')) {
|
||||
lastBuilds.set('isLoading', false);
|
||||
} else {
|
||||
apiEndpoint = config.apiEndpoint;
|
||||
repoId = this.get('build.repository.id');
|
||||
branchName = this.get('build.name');
|
||||
options = {};
|
||||
if (this.get('auth.signedIn')) {
|
||||
options.headers = {
|
||||
Authorization: "token " + (this.auth.token())
|
||||
};
|
||||
}
|
||||
$.ajax(apiEndpoint + "/v3/repo/" + repoId + "/builds?branch.name=" + branchName + "&limit=5&build.event_type=push,api", options).then(function(response) {
|
||||
var array, i, j, ref;
|
||||
array = response.builds.map(function(build) {
|
||||
return Ember.Object.create(build);
|
||||
});
|
||||
if (array.length < 5) {
|
||||
for (i = j = 1, ref = 5 - array.length; j <= ref; i = j += 1) {
|
||||
array.push({});
|
||||
}
|
||||
}
|
||||
lastBuilds.set('count', response['@pagination'].count);
|
||||
lastBuilds.set('content', array);
|
||||
return lastBuilds.set('isLoading', false);
|
||||
});
|
||||
}
|
||||
return lastBuilds;
|
||||
}.property(),
|
||||
|
||||
canTrigger: function() {
|
||||
var permissions;
|
||||
if (!this.get('auth.signedIn')) {
|
||||
return false;
|
||||
} else {
|
||||
permissions = this.get('auth.currentUser.permissions');
|
||||
if (permissions.contains(parseInt(this.get('build.repository.id')))) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}.property(),
|
||||
|
||||
triggerBuild: function() {
|
||||
var apiEndpoint, options, repoId;
|
||||
apiEndpoint = config.apiEndpoint;
|
||||
repoId = this.get('build.repository.id');
|
||||
options = {
|
||||
type: 'POST',
|
||||
body: {
|
||||
request: {
|
||||
branch: this.get('build.name')
|
||||
}
|
||||
}
|
||||
};
|
||||
if (this.get('auth.signedIn')) {
|
||||
options.headers = {
|
||||
Authorization: "token " + (this.auth.token())
|
||||
};
|
||||
}
|
||||
return $.ajax(apiEndpoint + "/v3/repo/" + repoId + "/requests", options).then(() => {
|
||||
this.set('isTriggering', false);
|
||||
return this.set('hasTriggered', true);
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
tiggerBuild(branch) {
|
||||
this.set('isTriggering', true);
|
||||
return this.triggerBuild();
|
||||
},
|
||||
|
||||
viewAllBuilds(branch) {
|
||||
return this.get('routing').transitionTo('builds');
|
||||
}
|
||||
}
|
||||
});
|
24
app/components/broadcast-tower.coffee
Normal file
24
app/components/broadcast-tower.coffee
Normal file
|
@ -0,0 +1,24 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
BroadcastTowerComponent = Ember.Component.extend
|
||||
|
||||
classNames: ['broadcast']
|
||||
|
||||
isOpen: false
|
||||
timeoutId: ''
|
||||
|
||||
actions:
|
||||
toggleBroadcasts:() ->
|
||||
@toggleProperty('isOpen')
|
||||
@sendAction('toggleBroadcasts')
|
||||
|
||||
if @get('isOpen') == true
|
||||
@set('timeoutId', setTimeout =>
|
||||
@toggleProperty('isOpen')
|
||||
@sendAction('toggleBroadcasts')
|
||||
, 10000
|
||||
)
|
||||
else
|
||||
clearTimeout(@get('timeoutId'))
|
||||
|
||||
`export default BroadcastTowerComponent`
|
|
@ -1,21 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['broadcast'],
|
||||
isOpen: false,
|
||||
timeoutId: '',
|
||||
actions: {
|
||||
toggleBroadcasts() {
|
||||
this.toggleProperty('isOpen');
|
||||
this.sendAction('toggleBroadcasts');
|
||||
if (this.get('isOpen') === true) {
|
||||
return this.set('timeoutId', setTimeout(() => {
|
||||
this.toggleProperty('isOpen');
|
||||
return this.sendAction('toggleBroadcasts');
|
||||
}, 10000));
|
||||
} else {
|
||||
return clearTimeout(this.get('timeoutId'));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
41
app/components/build-header.coffee
Normal file
41
app/components/build-header.coffee
Normal file
|
@ -0,0 +1,41 @@
|
|||
`import Ember from 'ember'`
|
||||
`import { gravatarImage } from 'travis/utils/urls'`
|
||||
`import GithubUrlPropertievs from 'travis/mixins/github-url-properties'`
|
||||
`import { durationFrom, safe } from 'travis/utils/helpers'`
|
||||
`import { githubCommit } from 'travis/utils/urls'`
|
||||
|
||||
BuildHeaderComponent = Ember.Component.extend
|
||||
|
||||
tagName: 'section'
|
||||
classNames: ['build-header']
|
||||
classNameBindings: ['item.state']
|
||||
|
||||
committerAvatarUrl: (->
|
||||
if url = @get('commit.committerAvatarUrl')
|
||||
url
|
||||
else
|
||||
email = @get('commit.committerEmail')
|
||||
gravatarImage(email, 40)
|
||||
).property('commit.committerEmail', 'commit.committerAvatarUrl')
|
||||
|
||||
authorAvatarUrl: (->
|
||||
if url = @get('commit.authorAvatarUrl')
|
||||
url
|
||||
else
|
||||
email = @get('commit.authorEmail')
|
||||
gravatarImage(email, 40)
|
||||
).property('commit.authorEmail', 'commit.authorAvatarUrl')
|
||||
|
||||
isJob: (->
|
||||
if @get('item.build') then true else false
|
||||
).property('item')
|
||||
|
||||
urlGithubCommit: (->
|
||||
githubCommit(@get('repo.slug'), @get('commit.sha'))
|
||||
).property('item')
|
||||
|
||||
elapsedTime: (->
|
||||
durationFrom(@get('item.startedAt'), @get('item.finishedAt'))
|
||||
).property('item.startedAt', 'item.finishedAt', 'item.duration')
|
||||
|
||||
`export default BuildHeaderComponent`
|
|
@ -1,27 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import { gravatarImage } from 'travis/utils/urls';
|
||||
import GithubUrlProperties from 'travis/mixins/github-url-properties';
|
||||
import { durationFrom, safe } from 'travis/utils/helpers';
|
||||
import { githubCommit } from 'travis/utils/urls';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'section',
|
||||
classNames: ['build-header'],
|
||||
classNameBindings: ['item.state'],
|
||||
|
||||
isJob: function() {
|
||||
if (this.get('item.build')) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}.property('item'),
|
||||
|
||||
urlGithubCommit: function() {
|
||||
return githubCommit(this.get('repo.slug'), this.get('commit.sha'));
|
||||
}.property('item'),
|
||||
|
||||
elapsedTime: function() {
|
||||
return durationFrom(this.get('item.startedAt'), this.get('item.finishedAt'));
|
||||
}.property('item.startedAt', 'item.finishedAt', 'item.duration')
|
||||
});
|
9
app/components/build-repo-actions.coffee
Normal file
9
app/components/build-repo-actions.coffee
Normal file
|
@ -0,0 +1,9 @@
|
|||
`import Ember from 'ember'`
|
||||
`import RepoActionsItemComponentMixin from 'travis/utils/repo-actions-item-component-mixin'`
|
||||
|
||||
BuildRepoActionsComponent = Ember.Component.extend(RepoActionsItemComponentMixin,
|
||||
item: Ember.computed.alias('build')
|
||||
type: 'build'
|
||||
)
|
||||
|
||||
`export default BuildRepoActionsComponent`
|
|
@ -1,7 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import RepoActionsItemComponentMixin from 'travis/utils/repo-actions-item-component-mixin';
|
||||
|
||||
export default Ember.Component.extend(RepoActionsItemComponentMixin, {
|
||||
item: Ember.computed.alias('build'),
|
||||
type: 'build'
|
||||
});
|
14
app/components/build-tile.coffee
Normal file
14
app/components/build-tile.coffee
Normal file
|
@ -0,0 +1,14 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
BuildTileComponent = Ember.Component.extend
|
||||
|
||||
tagName: 'li'
|
||||
classNameBindings: ['build.state']
|
||||
attributeBindings: ['title'],
|
||||
|
||||
title: (->
|
||||
num = @get('build.number')
|
||||
"##{num}"
|
||||
).property('build')
|
||||
|
||||
`export default BuildTileComponent`
|
|
@ -1,14 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'li',
|
||||
classNameBindings: ['build.state'],
|
||||
attributeBindings: ['title'],
|
||||
|
||||
title: function() {
|
||||
var num, state;
|
||||
num = this.get('build.number');
|
||||
state = this.get('build.state');
|
||||
return "Build #" + num + " " + state;
|
||||
}.property('build')
|
||||
});
|
|
@ -1,12 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import { colorForState } from 'travis/utils/helpers';
|
||||
import Polling from 'travis/mixins/polling';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNameBindings: ['color'],
|
||||
pollModels: 'build',
|
||||
|
||||
color: function() {
|
||||
return colorForState(this.get('build.state'));
|
||||
}.property('build.state')
|
||||
});
|
22
app/components/builds-item.coffee
Normal file
22
app/components/builds-item.coffee
Normal file
|
@ -0,0 +1,22 @@
|
|||
`import Ember from 'ember'`
|
||||
`import { gravatarImage } from 'travis/utils/urls'`
|
||||
`import { githubCommit as githubCommitUrl } from 'travis/utils/urls'`
|
||||
|
||||
BuildsItemComponent = Ember.Component.extend
|
||||
tagName: 'li'
|
||||
classNameBindings: ['build.state']
|
||||
classNames: ['row-li', 'pr-row']
|
||||
|
||||
authorAvatarUrl: (->
|
||||
if url = @get('build.commit.authorAvatarUrl')
|
||||
url
|
||||
else
|
||||
email = @get('build.commit.authorEmail')
|
||||
gravatarImage(email, 40)
|
||||
).property('build.commit.authorEmail', 'build.commit.authorAvatarUrl')
|
||||
|
||||
urlGithubCommit: (->
|
||||
githubCommitUrl(@get('build.repo.slug'), @get('build.commit.sha'))
|
||||
).property('build.commit.sha')
|
||||
|
||||
`export default BuildsItemComponent`
|
|
@ -1,12 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import { githubCommit as githubCommitUrl } from 'travis/utils/urls';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'li',
|
||||
classNameBindings: ['build.state'],
|
||||
classNames: ['row-li', 'pr-row'],
|
||||
|
||||
urlGithubCommit: function() {
|
||||
return githubCommitUrl(this.get('build.repo.slug'), this.get('build.commit.sha'));
|
||||
}.property('build.commit.sha')
|
||||
});
|
|
@ -1,30 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import Polling from 'travis/mixins/polling';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
store: Ember.inject.service('store'),
|
||||
|
||||
pollHook: function(store) {
|
||||
var contentType, repositoryId;
|
||||
contentType = this.get('contentType');
|
||||
repositoryId = this.get('repo.id');
|
||||
store = this.get('store');
|
||||
|
||||
if (contentType === 'builds') {
|
||||
return store.query('build', {
|
||||
event_type: 'push',
|
||||
repository_id: repositoryId
|
||||
});
|
||||
} else if (contentType === 'pull_requests') {
|
||||
return store.filter('build', {
|
||||
event_type: 'pull_request',
|
||||
repository_id: repositoryId
|
||||
});
|
||||
} else {
|
||||
return store.query('build', {
|
||||
repository_id: repositoryId,
|
||||
branches: true
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
27
app/components/caches-item.coffee
Normal file
27
app/components/caches-item.coffee
Normal file
|
@ -0,0 +1,27 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
CachesItemComponent = Ember.Component.extend
|
||||
ajax: Ember.inject.service()
|
||||
|
||||
tagName: 'li'
|
||||
classNames: ['cache-item']
|
||||
classNameBindings: ['cache.type']
|
||||
isDeleting: false
|
||||
|
||||
actions:
|
||||
delete: ->
|
||||
return if @get('isDeleting')
|
||||
|
||||
if confirm('Are you sure?')
|
||||
@set('isDeleting', true)
|
||||
|
||||
data = { branch: @get('cache.branch') }
|
||||
|
||||
deletingDone = => @set('isDeleting', false)
|
||||
|
||||
repo = @get('repo')
|
||||
@get('ajax').ajax("/repos/#{repo.get('id')}/caches", "DELETE", data: data).then(deletingDone, deletingDone).then =>
|
||||
@get('caches').removeObject(@get('cache'))
|
||||
|
||||
|
||||
`export default CachesItemComponent`
|
|
@ -1,33 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
ajax: Ember.inject.service(),
|
||||
tagName: 'li',
|
||||
classNames: ['cache-item'],
|
||||
classNameBindings: ['cache.type'],
|
||||
isDeleting: false,
|
||||
|
||||
actions: {
|
||||
"delete": function() {
|
||||
var data, deletingDone, repo;
|
||||
if (this.get('isDeleting')) {
|
||||
return;
|
||||
}
|
||||
if (confirm('Are you sure?')) {
|
||||
this.set('isDeleting', true);
|
||||
data = {
|
||||
branch: this.get('cache.branch')
|
||||
};
|
||||
deletingDone = () => {
|
||||
return this.set('isDeleting', false);
|
||||
};
|
||||
repo = this.get('repo');
|
||||
return this.get('ajax').ajax("/repos/" + (repo.get('id')) + "/caches", "DELETE", {
|
||||
data: data
|
||||
}).then(deletingDone, deletingDone).then(() => {
|
||||
return this.get('caches').removeObject(this.get('cache'));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
10
app/components/code-climate-popup.coffee
Normal file
10
app/components/code-climate-popup.coffee
Normal file
|
@ -0,0 +1,10 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
Component = Ember.Component.extend(
|
||||
actions:
|
||||
close: ->
|
||||
$('.popup').removeClass('display')
|
||||
return false
|
||||
)
|
||||
|
||||
`export default Component`
|
55
app/components/dashboard-row.coffee
Normal file
55
app/components/dashboard-row.coffee
Normal file
|
@ -0,0 +1,55 @@
|
|||
`import Ember from 'ember'`
|
||||
`import { githubCommit as githubCommitUrl } from 'travis/utils/urls'`
|
||||
`import config from 'travis/config/environment'`
|
||||
|
||||
DashboardRowComponent = Ember.Component.extend
|
||||
|
||||
tagName: 'li'
|
||||
classNameBindings: ['repo.default_branch.last_build.state']
|
||||
classNames: ['dashboard-row', 'row-li']
|
||||
isLoading: false
|
||||
isTriggering: false
|
||||
hasTriggered: false
|
||||
|
||||
urlGithubCommit: (->
|
||||
githubCommitUrl(@get('repo.slug'), @get('repo.default_branch.last_build.commit.sha'))
|
||||
).property('repo')
|
||||
|
||||
# canTrigger: (->
|
||||
# if !@get('auth.signedIn')
|
||||
# false
|
||||
# else
|
||||
# permissions = @get('auth.currentUser.permissions')
|
||||
# if permissions.contains parseInt(@get('build.repository.id'))
|
||||
# true
|
||||
# else
|
||||
# false
|
||||
# ).property()
|
||||
|
||||
# triggerBuild: (->
|
||||
# apiEndpoint = config.apiEndpoint
|
||||
# repoId = @get('build.repository.id')
|
||||
# options = {
|
||||
# type: 'POST',
|
||||
# body: {
|
||||
# request: {
|
||||
# branch: @get('build.name')
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# if @get('auth.signedIn')
|
||||
# options.headers = { Authorization: "token #{@auth.token()}" }
|
||||
# $.ajax("#{apiEndpoint}/v3/repo/#{repoId}/requests", options).then (response) =>
|
||||
# @set('isTriggering', false)
|
||||
# @set('hasTriggered', true)
|
||||
# )
|
||||
|
||||
actions:
|
||||
tiggerBuild: (branch) ->
|
||||
@set('isTriggering', true)
|
||||
@triggerBuild()
|
||||
|
||||
# viewAllBuilds: (branch) ->
|
||||
# @get('routing').transitionTo('builds')
|
||||
|
||||
`export default DashboardRowComponent`
|
|
@ -1,36 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import { githubCommit as githubCommitUrl } from 'travis/utils/urls';
|
||||
import config from 'travis/config/environment';
|
||||
import { hasAdminPermission, hasPushPermission } from 'travis/utils/permission';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'li',
|
||||
classNameBindings: ['repo.default_branch.last_build.state'],
|
||||
classNames: ['rows', 'rows--dashboard'],
|
||||
isLoading: false,
|
||||
isTriggering: false,
|
||||
hasTriggered: false,
|
||||
dropupIsOpen: false,
|
||||
|
||||
urlGithubCommit: function() {
|
||||
return githubCommitUrl(this.get('repo.slug'), this.get('repo.default_branch.last_build.commit.sha'));
|
||||
}.property('repo'),
|
||||
|
||||
displayMenuTofu: function() {
|
||||
return hasPushPermission(this.get('currentUser'), this.get('repo.id'));
|
||||
},
|
||||
|
||||
displayActivateLink: function() {
|
||||
return hasAdminPermission(this.get('currentUser'), this.get('repo.id'));
|
||||
},
|
||||
|
||||
actions: {
|
||||
tiggerBuild(branch) {
|
||||
this.set('isTriggering', true);
|
||||
return this.triggerBuild();
|
||||
},
|
||||
openDropup() {
|
||||
this.toggleProperty('dropupIsOpen');
|
||||
}
|
||||
}
|
||||
});
|
29
app/components/env-var.coffee
Normal file
29
app/components/env-var.coffee
Normal file
|
@ -0,0 +1,29 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
EnvVarComponent = Ember.Component.extend
|
||||
|
||||
classNames: ['settings-envvar']
|
||||
classNameBindings: ['envVar.public:is-public']
|
||||
|
||||
isDeleting: false
|
||||
|
||||
validates:
|
||||
name: ['presence']
|
||||
|
||||
actionType: 'Save'
|
||||
showValueField: Ember.computed.alias('public')
|
||||
|
||||
value: ( (key, value) ->
|
||||
if @get('envVar.public')
|
||||
@get('envVar.value')
|
||||
else
|
||||
'••••••••••••••••'
|
||||
).property('envVar.value', 'envVar.public')
|
||||
|
||||
actions:
|
||||
delete: ->
|
||||
return if @get('isDeleting')
|
||||
@set('isDeleting', true)
|
||||
@get('envVar').destroyRecord()
|
||||
|
||||
`export default EnvVarComponent`
|
|
@ -1,28 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['settings-envvar'],
|
||||
classNameBindings: ['envVar.public:is-public'],
|
||||
isDeleting: false,
|
||||
validates: { name: ['presence'] },
|
||||
actionType: 'Save',
|
||||
showValueField: Ember.computed.alias('public'),
|
||||
|
||||
value: function(key) {
|
||||
if (this.get('envVar.public')) {
|
||||
return this.get('envVar.value');
|
||||
} else {
|
||||
return '••••••••••••••••';
|
||||
}
|
||||
}.property('envVar.value', 'envVar.public'),
|
||||
|
||||
actions: {
|
||||
"delete": function() {
|
||||
if (this.get('isDeleting')) {
|
||||
return;
|
||||
}
|
||||
this.set('isDeleting', true);
|
||||
return this.get('envVar').destroyRecord();
|
||||
}
|
||||
}
|
||||
});
|
8
app/components/eye-icon.coffee
Normal file
8
app/components/eye-icon.coffee
Normal file
|
@ -0,0 +1,8 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
EyeIconComponent = Ember.Component.extend
|
||||
|
||||
tagName: 'span'
|
||||
classNames: ['icon-eye']
|
||||
|
||||
`export default EyeIconComponent`
|
|
@ -1,6 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'span',
|
||||
classNames: ['icon-eye']
|
||||
});
|
15
app/components/flash-display.coffee
Normal file
15
app/components/flash-display.coffee
Normal file
|
@ -0,0 +1,15 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
FlashDisplayComponent = Ember.Component.extend
|
||||
flashes: Ember.inject.service()
|
||||
|
||||
classNames: ['flash']
|
||||
tagName: 'ul'
|
||||
|
||||
messagesBinding: 'flashes.messages'
|
||||
|
||||
actions:
|
||||
closeMessage: (msg) ->
|
||||
@get('flashes').close(msg)
|
||||
|
||||
`export default FlashDisplayComponent`
|
|
@ -1,14 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
flashes: Ember.inject.service(),
|
||||
classNames: ['flash'],
|
||||
tagName: 'ul',
|
||||
messagesBinding: 'flashes.messages',
|
||||
|
||||
actions: {
|
||||
closeMessage(msg) {
|
||||
return this.get('flashes').close(msg);
|
||||
}
|
||||
}
|
||||
});
|
15
app/components/flash-item.coffee
Normal file
15
app/components/flash-item.coffee
Normal file
|
@ -0,0 +1,15 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
FlashItemComponent = Ember.Component.extend
|
||||
tagName: 'li'
|
||||
classNameBindings: ['type']
|
||||
|
||||
type: (->
|
||||
@get('flash.type') || 'broadcast'
|
||||
).property('flash.type')
|
||||
|
||||
actions:
|
||||
close: ->
|
||||
this.attrs.close(@get('flash'))
|
||||
|
||||
`export default FlashItemComponent`
|
|
@ -1,16 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'li',
|
||||
classNameBindings: ['type'],
|
||||
|
||||
type: function() {
|
||||
return this.get('flash.type') || 'broadcast';
|
||||
}.property('flash.type'),
|
||||
|
||||
actions: {
|
||||
close() {
|
||||
return this.attrs.close(this.get('flash'));
|
||||
}
|
||||
}
|
||||
});
|
18
app/components/hook-switch.coffee
Normal file
18
app/components/hook-switch.coffee
Normal file
|
@ -0,0 +1,18 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
HookSwitchComponent = Ember.Component.extend
|
||||
tagName: 'a'
|
||||
classNames: ['switch--icon']
|
||||
classNameBindings: ['active']
|
||||
activeBinding: "hook.active"
|
||||
|
||||
click: ->
|
||||
@sendAction('onToggle')
|
||||
hook = @get('hook')
|
||||
hook.toggle().then( (->), =>
|
||||
@toggleProperty('hook.active')
|
||||
@sendAction('onToggleError', hook)
|
||||
)
|
||||
|
||||
|
||||
`export default HookSwitchComponent`
|
|
@ -1,17 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'a',
|
||||
classNames: ['switch--icon'],
|
||||
classNameBindings: ['active'],
|
||||
activeBinding: "hook.active",
|
||||
click() {
|
||||
var hook;
|
||||
this.sendAction('onToggle');
|
||||
hook = this.get('hook');
|
||||
return hook.toggle().then((function() {}), () => {
|
||||
this.toggleProperty('hook.active');
|
||||
return this.sendAction('onToggleError', hook);
|
||||
});
|
||||
}
|
||||
});
|
21
app/components/hooks-list-item.coffee
Normal file
21
app/components/hooks-list-item.coffee
Normal file
|
@ -0,0 +1,21 @@
|
|||
`import Ember from 'ember'`
|
||||
`import config from 'travis/config/environment'`
|
||||
|
||||
HooksListItemComponent = Ember.Component.extend
|
||||
tagName: 'li'
|
||||
classNames: ['row']
|
||||
classNameBindings: ['hook.active:active']
|
||||
|
||||
githubOrgsOauthAccessSettingsUrl: config.githubOrgsOauthAccessSettingsUrl
|
||||
|
||||
actions:
|
||||
handleToggleError: ->
|
||||
@set("showError", true)
|
||||
|
||||
close: ->
|
||||
@send('resetErrors')
|
||||
|
||||
resetErrors: ->
|
||||
@set("showError", false)
|
||||
|
||||
`export default HooksListItemComponent`
|
|
@ -1,23 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import config from 'travis/config/environment';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'li',
|
||||
classNames: ['row'],
|
||||
classNameBindings: ['hook.active:active'],
|
||||
githubOrgsOauthAccessSettingsUrl: config.githubOrgsOauthAccessSettingsUrl,
|
||||
|
||||
actions: {
|
||||
handleToggleError() {
|
||||
return this.set("showError", true);
|
||||
},
|
||||
|
||||
close() {
|
||||
return this.send('resetErrors');
|
||||
},
|
||||
|
||||
resetErrors() {
|
||||
return this.set("showError", false);
|
||||
}
|
||||
}
|
||||
});
|
30
app/components/job-log.coffee
Normal file
30
app/components/job-log.coffee
Normal file
|
@ -0,0 +1,30 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
JobLogComponent = Ember.Component.extend
|
||||
logBinding: 'job.log'
|
||||
|
||||
didInsertElement: ->
|
||||
@setupLog()
|
||||
|
||||
logDidChange: (->
|
||||
@setupLog()
|
||||
).observes('log')
|
||||
|
||||
logWillChange: (->
|
||||
@teardownLog()
|
||||
).observesBefore('log')
|
||||
|
||||
willDestroyElement: ->
|
||||
@teardownLog()
|
||||
|
||||
teardownLog: ->
|
||||
job = @get('job')
|
||||
job.unsubscribe() if job
|
||||
|
||||
setupLog: ->
|
||||
job = @get('job')
|
||||
if job
|
||||
job.get('log').fetch()
|
||||
job.subscribe()
|
||||
|
||||
`export default JobLogComponent`
|
|
@ -1,35 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
logBinding: 'job.log',
|
||||
classNames: ['job-log'],
|
||||
|
||||
didReceiveAttrs: function(options) {
|
||||
this._super(...arguments);
|
||||
|
||||
let oldJob = options.oldAttrs && options.oldAttrs.job && options.oldAttrs.job.value,
|
||||
newJob = options.newAttrs && options.newAttrs.job && options.newAttrs.job.value;
|
||||
|
||||
if(newJob !== oldJob) {
|
||||
if(newJob) {
|
||||
this.setupLog(newJob);
|
||||
}
|
||||
|
||||
if(oldJob) {
|
||||
this.teardownLog(oldJob);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
teardownLog(job) {
|
||||
job.unsubscribe();
|
||||
},
|
||||
|
||||
setupLog(job) {
|
||||
this.set('error', false);
|
||||
job.get('log').fetch().then(function() { }, () => {
|
||||
this.set('error', true);
|
||||
});
|
||||
job.subscribe();
|
||||
}
|
||||
});
|
9
app/components/job-repo-actions.coffee
Normal file
9
app/components/job-repo-actions.coffee
Normal file
|
@ -0,0 +1,9 @@
|
|||
`import Ember from 'ember'`
|
||||
`import RepoActionsItemComponentMixin from 'travis/utils/repo-actions-item-component-mixin'`
|
||||
|
||||
JobRepoActionsComponent = Ember.Component.extend(RepoActionsItemComponentMixin,
|
||||
item: Ember.computed.alias('job')
|
||||
type: 'job'
|
||||
)
|
||||
|
||||
`export default JobRepoActionsComponent`
|
|
@ -1,7 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import RepoActionsItemComponentMixin from 'travis/utils/repo-actions-item-component-mixin';
|
||||
|
||||
export default Ember.Component.extend(RepoActionsItemComponentMixin, {
|
||||
item: Ember.computed.alias('job'),
|
||||
type: 'job'
|
||||
});
|
|
@ -1,18 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import { colorForState } from 'travis/utils/helpers';
|
||||
import { githubCommit } from 'travis/utils/urls';
|
||||
import Polling from 'travis/mixins/polling';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
pollModels: 'job.build',
|
||||
commitBinding: 'job.commit',
|
||||
currentItemBinding: 'job',
|
||||
|
||||
color: function() {
|
||||
return colorForState(this.get('job.state'));
|
||||
}.property('job.state'),
|
||||
|
||||
urlGithubCommit: function() {
|
||||
return githubCommit(this.get('repo.slug'), this.get('commit.sha'));
|
||||
}.property('repo.slug', 'commit.sha')
|
||||
});
|
32
app/components/jobs-item.coffee
Normal file
32
app/components/jobs-item.coffee
Normal file
|
@ -0,0 +1,32 @@
|
|||
`import Ember from 'ember'`
|
||||
`import { colorForState } from 'travis/utils/helpers'`
|
||||
`import { languageConfigKeys } from 'travis/utils/keys-map';`
|
||||
|
||||
JobsItemComponent = Ember.Component.extend
|
||||
tagName: 'li'
|
||||
classNameBindings: ['job.state']
|
||||
classNames: ['jobs-item']
|
||||
|
||||
languages: (->
|
||||
output = []
|
||||
|
||||
if config = @get('job.config')
|
||||
for key, languageName of languageConfigKeys
|
||||
if version = config[key]
|
||||
output.push(languageName + ': ' + version)
|
||||
|
||||
gemfile = @get('job.config.gemfile')
|
||||
if gemfile && @get('job.config.env')
|
||||
output.push "Gemfile: #{gemfile}"
|
||||
|
||||
output.join(' ')
|
||||
).property('job.config')
|
||||
|
||||
environment: (->
|
||||
if env = @get('job.config.env')
|
||||
env
|
||||
else if gemfile = @get('job.config.gemfile')
|
||||
"Gemfile: #{gemfile}"
|
||||
).property('job.config.env', 'job.config.gemfile')
|
||||
|
||||
`export default JobsItemComponent`
|
|
@ -1,36 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import { colorForState } from 'travis/utils/helpers';
|
||||
import { languageConfigKeys } from 'travis/utils/keys-map';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'li',
|
||||
classNameBindings: ['job.state'],
|
||||
classNames: ['jobs-item'],
|
||||
|
||||
languages: function() {
|
||||
var config, gemfile, key, languageName, output, version;
|
||||
output = [];
|
||||
if (config = this.get('job.config')) {
|
||||
for (key in languageConfigKeys) {
|
||||
languageName = languageConfigKeys[key];
|
||||
if (version = config[key]) {
|
||||
output.push(languageName + ': ' + version);
|
||||
}
|
||||
}
|
||||
gemfile = this.get('job.config.gemfile');
|
||||
if (gemfile && this.get('job.config.env')) {
|
||||
output.push("Gemfile: " + gemfile);
|
||||
}
|
||||
}
|
||||
return output.join(' ');
|
||||
}.property('job.config'),
|
||||
|
||||
environment: function() {
|
||||
var env, gemfile;
|
||||
if (env = this.get('job.config.env')) {
|
||||
return env;
|
||||
} else if (gemfile = this.get('job.config.gemfile')) {
|
||||
return "Gemfile: " + gemfile;
|
||||
}
|
||||
}.property('job.config.env', 'job.config.gemfile')
|
||||
});
|
15
app/components/jobs-list.coffee
Normal file
15
app/components/jobs-list.coffee
Normal file
|
@ -0,0 +1,15 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
JobsListComponent = Ember.Component.extend
|
||||
|
||||
tagName: 'section'
|
||||
classNames: ['jobs']
|
||||
|
||||
jobTableId: Ember.computed(->
|
||||
if @get('required')
|
||||
'jobs'
|
||||
else
|
||||
'allowed_failure_jobs'
|
||||
)
|
||||
|
||||
`export default JobsListComponent`
|
|
@ -1,13 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'section',
|
||||
classNames: ['jobs'],
|
||||
jobTableId: Ember.computed(function() {
|
||||
if (this.get('required')) {
|
||||
return 'jobs';
|
||||
} else {
|
||||
return 'allowed_failure_jobs';
|
||||
}
|
||||
})
|
||||
});
|
12
app/components/landing-row.coffee
Normal file
12
app/components/landing-row.coffee
Normal file
|
@ -0,0 +1,12 @@
|
|||
`import Ember from 'ember'`
|
||||
`import { githubCommit as githubCommitUrl } from 'travis/utils/urls'`
|
||||
`import TravisRoute from 'travis/routes/basic'`
|
||||
`import config from 'travis/config/environment'`
|
||||
|
||||
LandingRowComponent = Ember.Component.extend
|
||||
|
||||
tagName: 'li'
|
||||
classNameBindings: ['repo.lastBuildState']
|
||||
classNames: ['landing-row', 'row-li']
|
||||
|
||||
`export default LandingRowComponent`
|
|
@ -1,8 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
|
||||
tagName: 'li',
|
||||
classNameBindings: ['build.state']
|
||||
|
||||
});
|
40
app/components/limit-concurrent-builds.coffee
Normal file
40
app/components/limit-concurrent-builds.coffee
Normal file
|
@ -0,0 +1,40 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
LimitConcurrentBuildsComponent = Ember.Component.extend
|
||||
|
||||
classNames: ['limit-concurrent-builds']
|
||||
|
||||
description: (->
|
||||
description = "Limit concurrent jobs"
|
||||
if @get('enabled')
|
||||
description += " "
|
||||
description
|
||||
).property('enabled')
|
||||
|
||||
limitChanged: ->
|
||||
repo = @get('repo')
|
||||
limit = parseInt(@get('value'))
|
||||
if limit
|
||||
@set('isSaving', true)
|
||||
savingFinished = =>
|
||||
@set('isSaving', false)
|
||||
|
||||
repo.saveSettings(maximum_number_of_builds: limit).
|
||||
then(savingFinished, savingFinished)
|
||||
actions:
|
||||
toggle: ->
|
||||
unless @get('enabled')
|
||||
return if @get('value') == 0
|
||||
return if @get('isSaving')
|
||||
@set('isSaving', true)
|
||||
|
||||
savingFinished = =>
|
||||
@set('isSaving', false)
|
||||
|
||||
@get('repo').saveSettings(maximum_number_of_builds: 0).then(savingFinished, savingFinished)
|
||||
@set('value', 0)
|
||||
|
||||
limitChanged: ->
|
||||
Ember.run.debounce(this, 'limitChanged', 1000)
|
||||
|
||||
`export default LimitConcurrentBuildsComponent`
|
|
@ -1,55 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['limit-concurrent-builds'],
|
||||
|
||||
description: function() {
|
||||
var description;
|
||||
description = "Limit concurrent jobs";
|
||||
if (this.get('enabled')) {
|
||||
description += " ";
|
||||
}
|
||||
return description;
|
||||
}.property('enabled'),
|
||||
|
||||
limitChanged() {
|
||||
var limit, repo, savingFinished;
|
||||
repo = this.get('repo');
|
||||
limit = parseInt(this.get('value'));
|
||||
if (limit) {
|
||||
this.set('isSaving', true);
|
||||
savingFinished = () => {
|
||||
return this.set('isSaving', false);
|
||||
};
|
||||
return repo.saveSettings({
|
||||
maximum_number_of_builds: limit
|
||||
}).then(savingFinished, savingFinished);
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggle() {
|
||||
var savingFinished;
|
||||
if (!this.get('enabled')) {
|
||||
if (this.get('value') === 0) {
|
||||
return;
|
||||
}
|
||||
if (this.get('isSaving')) {
|
||||
return;
|
||||
}
|
||||
this.set('isSaving', true);
|
||||
savingFinished = () => {
|
||||
return this.set('isSaving', false);
|
||||
};
|
||||
this.get('repo').saveSettings({
|
||||
maximum_number_of_builds: 0
|
||||
}).then(savingFinished, savingFinished);
|
||||
return this.set('value', 0);
|
||||
}
|
||||
},
|
||||
|
||||
limitChanged() {
|
||||
return Ember.run.debounce(this, 'limitChanged', 1000);
|
||||
}
|
||||
}
|
||||
});
|
8
app/components/loading-indicator.coffee
Normal file
8
app/components/loading-indicator.coffee
Normal file
|
@ -0,0 +1,8 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
LoadingIndicatorComponent = Ember.Component.extend
|
||||
tagName: 'div'
|
||||
classNameBindings: ['center:loading-container', 'inline:inline-block', 'height:icon-height']
|
||||
center: false
|
||||
|
||||
`export default LoadingIndicatorComponent`
|
|
@ -1,7 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'div',
|
||||
classNameBindings: ['center:loading-container', 'inline:inline-block', 'height:icon-height'],
|
||||
center: false
|
||||
});
|
157
app/components/log-content.coffee
Normal file
157
app/components/log-content.coffee
Normal file
|
@ -0,0 +1,157 @@
|
|||
`import Ember from 'ember'`
|
||||
`import LinesSelector from 'travis/utils/lines-selector'`
|
||||
`import LogFolder from 'travis/utils/log-folder'`
|
||||
`import config from 'travis/config/environment'`
|
||||
`import { plainTextLog as plainTextLogUrl } from 'travis/utils/urls'`
|
||||
|
||||
Log.DEBUG = false
|
||||
Log.LIMIT = 10000
|
||||
|
||||
Log.Scroll = (options) ->
|
||||
options ||= {}
|
||||
@beforeScroll = options.beforeScroll
|
||||
this
|
||||
Log.Scroll.prototype = $.extend new Log.Listener,
|
||||
insert: (log, data, pos) ->
|
||||
@tryScroll() if @numbers
|
||||
true
|
||||
|
||||
tryScroll: ->
|
||||
if element = $("#log p:visible.highlight:first")
|
||||
if @beforeScroll
|
||||
@beforeScroll()
|
||||
$('#main').scrollTop(0)
|
||||
$('html, body').scrollTop(element.offset()?.top - (window.innerHeight / 3)) # weird, html works in chrome, body in firefox
|
||||
|
||||
Log.Limit = (max_lines, limitedLogCallback) ->
|
||||
@max_lines = max_lines || 1000
|
||||
@limitedLogCallback = limitedLogCallback || (->)
|
||||
this
|
||||
|
||||
Log.Limit.prototype = Log.extend new Log.Listener,
|
||||
count: 0,
|
||||
insert: (log, node, pos) ->
|
||||
if node.type == 'paragraph' && !node.hidden
|
||||
@count += 1
|
||||
if @limited
|
||||
@limitedLogCallback()
|
||||
return @count
|
||||
|
||||
Object.defineProperty Log.Limit.prototype, 'limited',
|
||||
get: ->
|
||||
@count >= @max_lines
|
||||
|
||||
LogContentComponent = Ember.Component.extend
|
||||
popup: Ember.inject.service()
|
||||
|
||||
currentUserBinding: 'auth.currentUser'
|
||||
|
||||
didInsertElement: ->
|
||||
console.log 'log view: did insert' if Log.DEBUG
|
||||
@_super.apply this, arguments
|
||||
@createEngine()
|
||||
|
||||
willDestroyElement: ->
|
||||
console.log 'log view: will destroy' if Log.DEBUG
|
||||
@teardownLog()
|
||||
|
||||
teardownLog: (log) ->
|
||||
if log || log = @get('log')
|
||||
parts = log.get('parts')
|
||||
parts.removeArrayObserver(@, didChange: 'partsDidChange', willChange: 'noop')
|
||||
parts.destroy()
|
||||
log.notifyPropertyChange('parts')
|
||||
@lineSelector?.willDestroy()
|
||||
if logElement = this.$('#log')
|
||||
logElement.empty()
|
||||
|
||||
createEngine: (log) ->
|
||||
if log || log = @get('log')
|
||||
if logElement = this.$('#log')
|
||||
logElement.empty()
|
||||
|
||||
log.onClear =>
|
||||
@teardownLog()
|
||||
@createEngine()
|
||||
|
||||
@scroll = new Log.Scroll beforeScroll: =>
|
||||
@unfoldHighlight()
|
||||
@limit = new Log.Limit Log.LIMIT, =>
|
||||
@set('limited', true)
|
||||
@engine = Log.create(listeners: [@scroll, @limit])
|
||||
@engine.limit = @limit
|
||||
@logFolder = new LogFolder(@$('#log'))
|
||||
@lineSelector = new LinesSelector(@$('#log'), @scroll, @logFolder)
|
||||
@observeParts(log)
|
||||
|
||||
didUpdateAttrs: (changes) ->
|
||||
@_super.apply(this, arguments)
|
||||
|
||||
return unless changes.oldAttrs
|
||||
|
||||
if changes.newAttrs.job.value && changes.oldAttrs.job.value &&
|
||||
changes.newAttrs.job.value != changes.oldAttrs.job.value
|
||||
|
||||
@teardownLog(changes.oldAttrs.job.value.get('log'))
|
||||
@createEngine(changes.newAttrs.job.value.get('log'))
|
||||
|
||||
unfoldHighlight: ->
|
||||
@lineSelector.unfoldLines()
|
||||
|
||||
observeParts: (log) ->
|
||||
if log || log = @get('log')
|
||||
parts = log.get('parts')
|
||||
parts.addArrayObserver(@, didChange: 'partsDidChange', willChange: 'noop')
|
||||
parts = parts.slice(0)
|
||||
@partsDidChange(parts, 0, null, parts.length)
|
||||
|
||||
partsDidChange: (parts, start, _, added) ->
|
||||
console.log 'log view: parts did change' if Log.DEBUG
|
||||
return unless @get('state') == 'inDOM'
|
||||
|
||||
for part, i in parts.slice(start, start + added)
|
||||
# console.log "limit in log view: #{@get('limited')}"
|
||||
break if @engine?.limit?.limited
|
||||
@engine.set(part.number, part.content)
|
||||
|
||||
plainTextLogUrl: (->
|
||||
if id = @get('log.job.id')
|
||||
url = plainTextLogUrl(id)
|
||||
if config.pro
|
||||
url += "&access_token=#{@get('job.log.token')}"
|
||||
url
|
||||
).property('job.log.id', 'job.log.token')
|
||||
|
||||
hasPermission: (->
|
||||
if permissions = @get('currentUser.permissions')
|
||||
permissions.contains parseInt(@get('job.repo.id'))
|
||||
).property('currentUser.permissions.length', 'job.repo.id')
|
||||
|
||||
canRemoveLog: (->
|
||||
if job = @get('job')
|
||||
job.get('canRemoveLog') && @get('hasPermission')
|
||||
).property('job.canRemoveLog', 'hasPermission')
|
||||
|
||||
showToTop: (->
|
||||
@get('log.hasContent') && @get('job.canRemoveLog')
|
||||
).property('log.hasContent', 'job.canRemoveLog')
|
||||
showTailing: Ember.computed.alias('showToTop')
|
||||
|
||||
actions:
|
||||
toTop: () ->
|
||||
Travis.tailing.stop()
|
||||
$(window).scrollTop(0)
|
||||
|
||||
toggleTailing: ->
|
||||
Travis.tailing.toggle()
|
||||
@engine.autoCloseFold = !Travis.tailing.isActive()
|
||||
event.preventDefault()
|
||||
|
||||
removeLogPopup: ->
|
||||
if @get('canRemoveLog')
|
||||
@get('popup').open('remove-log-popup')
|
||||
return false
|
||||
|
||||
noop: -> # TODO required?
|
||||
|
||||
`export default LogContentComponent`
|
|
@ -1,238 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import LinesSelector from 'travis/utils/lines-selector';
|
||||
import LogFolder from 'travis/utils/log-folder';
|
||||
import config from 'travis/config/environment';
|
||||
import { plainTextLog as plainTextLogUrl } from 'travis/utils/urls';
|
||||
|
||||
Log.DEBUG = false;
|
||||
|
||||
Log.LIMIT = 10000;
|
||||
|
||||
Log.Scroll = function(options) {
|
||||
options = options || {};
|
||||
this.beforeScroll = options.beforeScroll;
|
||||
return this;
|
||||
};
|
||||
|
||||
Log.Scroll.prototype = $.extend(new Log.Listener(), {
|
||||
insert: function(log, data, pos) {
|
||||
if (this.numbers) {
|
||||
this.tryScroll();
|
||||
}
|
||||
return true;
|
||||
},
|
||||
tryScroll: function() {
|
||||
var element, ref;
|
||||
if (element = $("#log p:visible.highlight:first")) {
|
||||
if (this.beforeScroll) {
|
||||
this.beforeScroll();
|
||||
}
|
||||
$('#main').scrollTop(0);
|
||||
return $('html, body').scrollTop(((ref = element.offset()) != null ? ref.top : void 0) - (window.innerHeight / 3));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Log.Limit = function(max_lines, limitedLogCallback) {
|
||||
this.max_lines = max_lines || 1000;
|
||||
this.limitedLogCallback = limitedLogCallback || (function() {});
|
||||
return this;
|
||||
};
|
||||
|
||||
Log.Limit.prototype = Log.extend(new Log.Listener(), {
|
||||
count: 0,
|
||||
insert: function(log, node, pos) {
|
||||
if (node.type === 'paragraph' && !node.hidden) {
|
||||
this.count += 1;
|
||||
if (this.limited) {
|
||||
this.limitedLogCallback();
|
||||
}
|
||||
return this.count;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Log.Limit.prototype, 'limited', {
|
||||
get: function() {
|
||||
return this.count >= this.max_lines;
|
||||
}
|
||||
});
|
||||
|
||||
export default Ember.Component.extend({
|
||||
popup: Ember.inject.service(),
|
||||
classNameBindings: ['logIsVisible:is-open'],
|
||||
logIsVisible: false,
|
||||
currentUserBinding: 'auth.currentUser',
|
||||
|
||||
didInsertElement() {
|
||||
if (Log.DEBUG) {
|
||||
console.log('log view: did insert');
|
||||
}
|
||||
this._super.apply(this, arguments);
|
||||
Ember.run.scheduleOnce('afterRender', this, 'createEngine');
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
if (Log.DEBUG) {
|
||||
console.log('log view: will destroy');
|
||||
}
|
||||
Ember.run.scheduleOnce('afterRender', this, 'teardownLog');
|
||||
},
|
||||
|
||||
teardownLog(log) {
|
||||
var parts, ref;
|
||||
if (log || (log = this.get('log'))) {
|
||||
parts = log.get('parts');
|
||||
parts.removeArrayObserver(this, {
|
||||
didChange: 'partsDidChange',
|
||||
willChange: 'noop'
|
||||
});
|
||||
parts.destroy();
|
||||
log.notifyPropertyChange('parts');
|
||||
if ((ref = this.lineSelector) != null) {
|
||||
ref.willDestroy();
|
||||
}
|
||||
this.clearLogElement();
|
||||
}
|
||||
},
|
||||
|
||||
clearLogElement() {
|
||||
var logElement = this.$('#log');
|
||||
if (logElement && logElement[0]) {
|
||||
logElement[0].innerHTML = '';
|
||||
}
|
||||
},
|
||||
|
||||
createEngine(log) {
|
||||
if (log || (log = this.get('log'))) {
|
||||
this.clearLogElement();
|
||||
log.onClear(() => {
|
||||
this.teardownLog();
|
||||
return this.createEngine();
|
||||
});
|
||||
this.scroll = new Log.Scroll({
|
||||
beforeScroll: () => {
|
||||
return this.unfoldHighlight();
|
||||
}
|
||||
});
|
||||
this.limit = new Log.Limit(Log.LIMIT, () => {
|
||||
return this.set('limited', true);
|
||||
});
|
||||
this.engine = Log.create({
|
||||
listeners: [this.scroll, this.limit]
|
||||
});
|
||||
this.engine.limit = this.limit;
|
||||
this.logFolder = new LogFolder(this.$('#log'));
|
||||
this.lineSelector = new LinesSelector(this.$('#log'), this.scroll, this.logFolder);
|
||||
this.observeParts(log);
|
||||
}
|
||||
},
|
||||
|
||||
didUpdateAttrs(changes) {
|
||||
this._super.apply(this, arguments);
|
||||
if (!changes.oldAttrs) {
|
||||
return;
|
||||
}
|
||||
if (changes.newAttrs.job.value && changes.oldAttrs.job.value && changes.newAttrs.job.value !== changes.oldAttrs.job.value) {
|
||||
this.teardownLog(changes.oldAttrs.job.value.get('log'));
|
||||
return this.createEngine(changes.newAttrs.job.value.get('log'));
|
||||
}
|
||||
},
|
||||
|
||||
unfoldHighlight() {
|
||||
return this.lineSelector.unfoldLines();
|
||||
},
|
||||
|
||||
observeParts(log) {
|
||||
var parts;
|
||||
if (log || (log = this.get('log'))) {
|
||||
parts = log.get('parts');
|
||||
parts.addArrayObserver(this, {
|
||||
didChange: 'partsDidChange',
|
||||
willChange: 'noop'
|
||||
});
|
||||
parts = parts.slice(0);
|
||||
this.partsDidChange(parts, 0, null, parts.length);
|
||||
}
|
||||
},
|
||||
|
||||
partsDidChange(parts, start, _, added) {
|
||||
Ember.run.schedule('afterRender', this, function() {
|
||||
var i, j, len, part, ref, ref1, ref2, results;
|
||||
if (Log.DEBUG) {
|
||||
console.log('log view: parts did change');
|
||||
}
|
||||
if (this.get('_state') !== 'inDOM') {
|
||||
return;
|
||||
}
|
||||
ref = parts.slice(start, start + added);
|
||||
results = [];
|
||||
for (i = j = 0, len = ref.length; j < len; i = ++j) {
|
||||
part = ref[i];
|
||||
if ((ref1 = this.engine) != null ? (ref2 = ref1.limit) != null ? ref2.limited : void 0 : void 0) {
|
||||
break;
|
||||
}
|
||||
results.push(this.engine.set(part.number, part.content));
|
||||
}
|
||||
return results;
|
||||
});
|
||||
},
|
||||
|
||||
plainTextLogUrl: function() {
|
||||
var id, url;
|
||||
if (id = this.get('log.job.id')) {
|
||||
url = plainTextLogUrl(id);
|
||||
if (config.pro) {
|
||||
url += "&access_token=" + (this.get('job.log.token'));
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}.property('job.log.id', 'job.log.token'),
|
||||
|
||||
hasPermission: function() {
|
||||
var permissions;
|
||||
if (permissions = this.get('currentUser.permissions')) {
|
||||
return permissions.contains(parseInt(this.get('job.repo.id')));
|
||||
}
|
||||
}.property('currentUser.permissions.length', 'job.repo.id'),
|
||||
|
||||
canRemoveLog: function() {
|
||||
var job;
|
||||
if (job = this.get('job')) {
|
||||
return job.get('canRemoveLog') && this.get('hasPermission');
|
||||
}
|
||||
}.property('job.canRemoveLog', 'hasPermission'),
|
||||
|
||||
showToTop: function() {
|
||||
return this.get('log.hasContent') && this.get('job.canRemoveLog');
|
||||
}.property('log.hasContent', 'job.canRemoveLog'),
|
||||
|
||||
showTailing: Ember.computed.alias('showToTop'),
|
||||
|
||||
actions: {
|
||||
toTop() {
|
||||
Travis.tailing.stop();
|
||||
return $(window).scrollTop(0);
|
||||
},
|
||||
|
||||
toggleTailing() {
|
||||
Travis.tailing.toggle();
|
||||
this.engine.autoCloseFold = !Travis.tailing.isActive();
|
||||
return false;
|
||||
},
|
||||
|
||||
removeLogPopup() {
|
||||
if (this.get('canRemoveLog')) {
|
||||
this.get('popup').open('remove-log-popup');
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
toggleLog() {
|
||||
this.toggleProperty('logIsVisible');
|
||||
}
|
||||
},
|
||||
|
||||
// don't remove this, it's needed as an empty willChange callback
|
||||
noop: function() {}
|
||||
});
|
19
app/components/no-builds.coffee
Normal file
19
app/components/no-builds.coffee
Normal file
|
@ -0,0 +1,19 @@
|
|||
`import Ember from 'ember'`
|
||||
`import config from 'travis/config/environment'`
|
||||
|
||||
NoBuildsComponent = Ember.Component.extend
|
||||
actions:
|
||||
triggerBuild: () ->
|
||||
@set('isLoading', true)
|
||||
apiEndpoint = config.apiEndpoint
|
||||
$.ajax(apiEndpoint + "/v3/repo/#{@get('repo.repo.id')}/requests", {
|
||||
headers: {
|
||||
Authorization: 'token ' + @get('repo.auth')
|
||||
},
|
||||
type: "POST"
|
||||
}).then( =>
|
||||
@set('isLoading', false)
|
||||
# @transitionToRoute('repo')
|
||||
);
|
||||
|
||||
`export default NoBuildsComponent`
|
|
@ -1,20 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import config from 'travis/config/environment';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
actions: {
|
||||
triggerBuild() {
|
||||
var apiEndpoint;
|
||||
this.set('isLoading', true);
|
||||
apiEndpoint = config.apiEndpoint;
|
||||
return $.ajax(apiEndpoint + ("/v3/repo/" + (this.get('repo.repo.id')) + "/requests"), {
|
||||
headers: {
|
||||
Authorization: 'token ' + this.get('repo.auth')
|
||||
},
|
||||
type: "POST"
|
||||
}).then(() => {
|
||||
return this.set('isLoading', false);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
5
app/components/no-repos.coffee
Normal file
5
app/components/no-repos.coffee
Normal file
|
@ -0,0 +1,5 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
NoReposComponent = Ember.Component.extend()
|
||||
|
||||
`export default NoReposComponent`
|
|
@ -1,3 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend();
|
5
app/components/not-active.coffee
Normal file
5
app/components/not-active.coffee
Normal file
|
@ -0,0 +1,5 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
NotActiveComponent = Ember.Component.extend()
|
||||
|
||||
`export default NotActiveComponent`
|
|
@ -1,3 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend();
|
28
app/components/org-item.coffee
Normal file
28
app/components/org-item.coffee
Normal file
|
@ -0,0 +1,28 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
OrgItemComponent = Ember.Component.extend
|
||||
|
||||
classNames: ['media', 'account']
|
||||
tagName: 'li'
|
||||
classNameBindings: ['type', 'selected']
|
||||
typeBinding: 'account.type'
|
||||
selectedBinding: 'account.selected'
|
||||
tokenIsVisible: false
|
||||
|
||||
name: (->
|
||||
@get('account.name') || @get('account.login')
|
||||
).property('account')
|
||||
|
||||
avatarUrl: (->
|
||||
@get('account.avatarUrl') || false
|
||||
).property('account')
|
||||
|
||||
isUser: (->
|
||||
@get('account.type') == 'user'
|
||||
).property('account')
|
||||
|
||||
actions:
|
||||
tokenVisibility: () ->
|
||||
@toggleProperty('tokenIsVisible')
|
||||
|
||||
`export default OrgItemComponent`
|
|
@ -1,28 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['media', 'account'],
|
||||
tagName: 'li',
|
||||
classNameBindings: ['type', 'selected'],
|
||||
typeBinding: 'account.type',
|
||||
selectedBinding: 'account.selected',
|
||||
tokenIsVisible: false,
|
||||
|
||||
name: function() {
|
||||
return this.get('account.name') || this.get('account.login');
|
||||
}.property('account'),
|
||||
|
||||
avatarUrl: function() {
|
||||
return this.get('account.avatarUrl') || false;
|
||||
}.property('account'),
|
||||
|
||||
isUser: function() {
|
||||
return this.get('account.type') === 'user';
|
||||
}.property('account'),
|
||||
|
||||
actions: {
|
||||
tokenVisibility() {
|
||||
return this.toggleProperty('tokenIsVisible');
|
||||
}
|
||||
}
|
||||
});
|
13
app/components/orgs-filter.coffee
Normal file
13
app/components/orgs-filter.coffee
Normal file
|
@ -0,0 +1,13 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
Component = Ember.Component.extend
|
||||
|
||||
actions:
|
||||
toggleOrgFilter: () ->
|
||||
@toggleProperty('showFilter')
|
||||
false
|
||||
select: (org) ->
|
||||
@toggleProperty('showFilter')
|
||||
@sendAction('action', org)
|
||||
|
||||
`export default Component`
|
|
@ -1,17 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
|
||||
classNames: ['organisation-filter'],
|
||||
actions: {
|
||||
toggleOrgFilter() {
|
||||
this.toggleProperty('showFilter');
|
||||
return false;
|
||||
},
|
||||
|
||||
select(org) {
|
||||
this.toggleProperty('showFilter');
|
||||
return this.sendAction('action', org);
|
||||
}
|
||||
}
|
||||
});
|
29
app/components/owner-repo-tile.coffee
Normal file
29
app/components/owner-repo-tile.coffee
Normal file
|
@ -0,0 +1,29 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
OwnerRepoTileComponent = Ember.Component.extend
|
||||
|
||||
tagName: 'li'
|
||||
classNames: ['owner-tile', 'row-li']
|
||||
classNameBindings: ['repo.default_branch.last_build.state']
|
||||
|
||||
ownerName: (->
|
||||
@get('repo.slug').split(/\//)[0]
|
||||
).property('repo.slug')
|
||||
|
||||
repoName: (->
|
||||
@get('repo.slug').split(/\//)[1]
|
||||
).property('repo.slug')
|
||||
|
||||
isAnimating: (->
|
||||
state = @get('repo.default_branch.last_build.state')
|
||||
animationStates = ['received', 'queued', 'started', 'booting']
|
||||
|
||||
unless animationStates.indexOf(state) == -1
|
||||
true
|
||||
|
||||
).property('repo.default_branch.last_build.state')
|
||||
|
||||
|
||||
|
||||
|
||||
`export default OwnerRepoTileComponent`
|
|
@ -1,24 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'li',
|
||||
classNames: ['owner-tile', 'row-li'],
|
||||
classNameBindings: ['repo.default_branch.last_build.state'],
|
||||
|
||||
ownerName: function() {
|
||||
return this.get('repo.slug').split(/\//)[0];
|
||||
}.property('repo.slug'),
|
||||
|
||||
repoName: function() {
|
||||
return this.get('repo.slug').split(/\//)[1];
|
||||
}.property('repo.slug'),
|
||||
|
||||
isAnimating: function() {
|
||||
var animationStates, state;
|
||||
state = this.get('repo.default_branch.last_build.state');
|
||||
animationStates = ['received', 'queued', 'started', 'booting'];
|
||||
if (animationStates.indexOf(state) !== -1) {
|
||||
return true;
|
||||
}
|
||||
}.property('repo.default_branch.last_build.state')
|
||||
});
|
6
app/components/owner-sync-button.coffee
Normal file
6
app/components/owner-sync-button.coffee
Normal file
|
@ -0,0 +1,6 @@
|
|||
`import Ember from 'ember'`
|
||||
`import SyncButton from 'travis/components/sync-button'`
|
||||
|
||||
Component = SyncButton.extend()
|
||||
|
||||
`export default Component`
|
|
@ -1,4 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import SyncButton from 'travis/components/sync-button';
|
||||
|
||||
export default SyncButton.extend();
|
|
@ -1,17 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
popup: Ember.inject.service(),
|
||||
classNames: ['application'],
|
||||
|
||||
click(event) {
|
||||
var targetAndParents = $(event.target).parents().andSelf();
|
||||
|
||||
if (!(targetAndParents.hasClass('open-popup') || targetAndParents.hasClass('popup'))) {
|
||||
this.get('popup').close();
|
||||
}
|
||||
if (!targetAndParents.hasClass('menu') && !targetAndParents.is('#tools > a')) {
|
||||
$('.menu').removeClass('display');
|
||||
}
|
||||
}
|
||||
});
|
|
@ -1,6 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: ['profile-orglist', 'columns', 'medium-4'],
|
||||
tagName: 'aside',
|
||||
});
|
16
app/components/queued-jobs.coffee
Normal file
16
app/components/queued-jobs.coffee
Normal file
|
@ -0,0 +1,16 @@
|
|||
`import Ember from 'ember'`
|
||||
`import config from 'travis/config/environment'`
|
||||
|
||||
QueuedJobsComponent = Ember.Component.extend
|
||||
store: Ember.inject.service()
|
||||
|
||||
init: ->
|
||||
@_super.apply this, arguments
|
||||
if !Ember.testing
|
||||
Visibility.every config.intervals.updateTimes, @updateTimes.bind(this)
|
||||
|
||||
updateTimes: ->
|
||||
if jobs = @get('jobs')
|
||||
jobs.forEach (job) -> job.updateTimes()
|
||||
|
||||
`export default QueuedJobsComponent`
|
|
@ -1,18 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import config from 'travis/config/environment';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
store: Ember.inject.service(),
|
||||
updateTimesService: Ember.inject.service('updateTimes'),
|
||||
|
||||
init() {
|
||||
this._super.apply(this, arguments);
|
||||
if (!Ember.testing) {
|
||||
return Visibility.every(config.intervals.updateTimes, this.updateTimes.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
updateTimes() {
|
||||
this.get('updateTimesService').push(this.get('jobs'));
|
||||
}
|
||||
});
|
23
app/components/remove-log-popup.coffee
Normal file
23
app/components/remove-log-popup.coffee
Normal file
|
@ -0,0 +1,23 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
Component = Ember.Component.extend(
|
||||
actions:
|
||||
close: ->
|
||||
$('.popup').removeClass('display')
|
||||
return false
|
||||
|
||||
removeLog: ->
|
||||
$('.popup').removeClass('display')
|
||||
job = @get('job')
|
||||
job.removeLog().then ->
|
||||
Travis.flash(success: 'Log has been successfully removed.')
|
||||
, (xhr) ->
|
||||
if xhr.status == 409
|
||||
Travis.flash(error: 'Log can\'t be removed')
|
||||
else if xhr.status == 401
|
||||
Travis.flash(error: 'You don\'t have sufficient access to remove the log')
|
||||
else
|
||||
Travis.flash(error: 'An error occured when removing the log')
|
||||
)
|
||||
|
||||
`export default Component`
|
|
@ -1,27 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
actions: {
|
||||
close() {
|
||||
$('.popup').removeClass('display');
|
||||
return false;
|
||||
},
|
||||
|
||||
removeLog() {
|
||||
var job = this.get('job');
|
||||
$('.popup').removeClass('display');
|
||||
|
||||
return job.removeLog().then(function() {
|
||||
return Travis.flash({ success: 'Log has been successfully removed.' });
|
||||
}, function(xhr) {
|
||||
if (xhr.status === 409) {
|
||||
return Travis.flash({ error: 'Log can\'t be removed' });
|
||||
} else if (xhr.status === 401) {
|
||||
return Travis.flash({ error: 'You don\'t have sufficient access to remove the log' });
|
||||
} else {
|
||||
return Travis.flash({ error: 'An error occured when removing the log' });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
15
app/components/repo-actions.coffee
Normal file
15
app/components/repo-actions.coffee
Normal file
|
@ -0,0 +1,15 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
RepoActionsComponent = Ember.Component.extend(
|
||||
displayCodeClimate: (->
|
||||
@get('repo.githubLanguage') == 'Ruby'
|
||||
).property('repo.githubLanguage')
|
||||
|
||||
actions:
|
||||
codeClimatePopup: ->
|
||||
$('.popup').removeClass('display')
|
||||
$('#code-climate').addClass('display')
|
||||
return false
|
||||
)
|
||||
|
||||
`export default RepoActionsComponent`
|
|
@ -1,7 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
|
||||
classNames: ['repo-main-tools']
|
||||
|
||||
});
|
55
app/components/repo-show-tabs.coffee
Normal file
55
app/components/repo-show-tabs.coffee
Normal file
|
@ -0,0 +1,55 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
RepoShowTabsComponent = Ember.Component.extend
|
||||
|
||||
tagName: 'nav'
|
||||
classNames: ['tabnav']
|
||||
ariaRole: 'tablist'
|
||||
|
||||
# hrm. how to parametrize bind-attr?
|
||||
classCurrent: (->
|
||||
'active' if @get('tab') == 'current'
|
||||
).property('tab')
|
||||
|
||||
classBuilds: (->
|
||||
'active' if @get('tab') == 'builds'
|
||||
).property('tab')
|
||||
|
||||
classPullRequests: (->
|
||||
'active' if @get('tab') == 'pull_requests'
|
||||
).property('tab')
|
||||
|
||||
classBranches: (->
|
||||
'active' if @get('tab') == 'branches'
|
||||
).property('tab')
|
||||
|
||||
classBuild: (->
|
||||
tab = @get('tab')
|
||||
classes = []
|
||||
classes.push('active') if tab == 'build'
|
||||
classes.push('display-inline') if tab == 'build' || tab == 'job'
|
||||
classes.join(' ')
|
||||
).property('tab')
|
||||
|
||||
# TODO: refactor tabs, most of the things here are not really DRY
|
||||
classJob: (->
|
||||
'active' if @get('tab') == 'job'
|
||||
).property('tab')
|
||||
|
||||
classRequests: (->
|
||||
'active' if @get('tab') == 'requests'
|
||||
).property('tab')
|
||||
|
||||
classCaches: (->
|
||||
'active' if @get('tab') == 'caches'
|
||||
).property('tab')
|
||||
|
||||
classSettings: (->
|
||||
'active' if @get('tab') == 'settings'
|
||||
).property('tab')
|
||||
|
||||
classRequest: (->
|
||||
'active' if @get('tab') == 'request'
|
||||
).property('tab')
|
||||
|
||||
`export default RepoShowTabsComponent`
|
|
@ -1,74 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'nav',
|
||||
classNames: ['tabnav'],
|
||||
ariaRole: 'tablist',
|
||||
|
||||
classCurrent: function() {
|
||||
if (this.get('tab') === 'current') {
|
||||
return 'active';
|
||||
}
|
||||
}.property('tab'),
|
||||
|
||||
classBuilds: function() {
|
||||
if (this.get('tab') === 'builds') {
|
||||
return 'active';
|
||||
}
|
||||
}.property('tab'),
|
||||
|
||||
classPullRequests: function() {
|
||||
if (this.get('tab') === 'pull_requests') {
|
||||
return 'active';
|
||||
}
|
||||
}.property('tab'),
|
||||
|
||||
classBranches: function() {
|
||||
if (this.get('tab') === 'branches') {
|
||||
return 'active';
|
||||
}
|
||||
}.property('tab'),
|
||||
|
||||
classBuild: function() {
|
||||
var classes, tab;
|
||||
tab = this.get('tab');
|
||||
classes = [];
|
||||
if (tab === 'build') {
|
||||
classes.push('active');
|
||||
}
|
||||
if (tab === 'build' || tab === 'job') {
|
||||
classes.push('display-inline');
|
||||
}
|
||||
return classes.join(' ');
|
||||
}.property('tab'),
|
||||
|
||||
classJob: function() {
|
||||
if (this.get('tab') === 'job') {
|
||||
return 'active';
|
||||
}
|
||||
}.property('tab'),
|
||||
|
||||
classRequests: function() {
|
||||
if (this.get('tab') === 'requests') {
|
||||
return 'active';
|
||||
}
|
||||
}.property('tab'),
|
||||
|
||||
classCaches: function() {
|
||||
if (this.get('tab') === 'caches') {
|
||||
return 'active';
|
||||
}
|
||||
}.property('tab'),
|
||||
|
||||
classSettings: function() {
|
||||
if (this.get('tab') === 'settings') {
|
||||
return 'active';
|
||||
}
|
||||
}.property('tab'),
|
||||
|
||||
classRequest: function() {
|
||||
if (this.get('tab') === 'request') {
|
||||
return 'active';
|
||||
}
|
||||
}.property('tab')
|
||||
});
|
49
app/components/repo-show-tools.coffee
Normal file
49
app/components/repo-show-tools.coffee
Normal file
|
@ -0,0 +1,49 @@
|
|||
`import Ember from 'ember'`
|
||||
`import config from 'travis/config/environment'`
|
||||
|
||||
RepoShowToolsComponent = Ember.Component.extend
|
||||
popup: Ember.inject.service()
|
||||
|
||||
classNames: ['settings-menu']
|
||||
classNameBindings: ['isOpen:display']
|
||||
isOpen: false
|
||||
|
||||
click: (event) ->
|
||||
if $(event.target).is('a') && $(event.target).parents('.settings-dropdown').length
|
||||
@closeMenu()
|
||||
|
||||
closeMenu: ->
|
||||
@toggleProperty('isOpen')
|
||||
|
||||
actions:
|
||||
menu: ->
|
||||
@toggleProperty('isOpen')
|
||||
|
||||
hasPermission: (->
|
||||
if permissions = @get('currentUser.permissions')
|
||||
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'))
|
||||
).property('currentUser.adminPermissions.length', 'repo.id')
|
||||
|
||||
displaySettingsLink: (->
|
||||
@get('hasPushPermission')
|
||||
).property('hasPushPermission')
|
||||
|
||||
displayCachesLink: (->
|
||||
@get('hasPushPermission') && config.endpoints.caches
|
||||
).property('hasPushPermission')
|
||||
|
||||
displayStatusImages: (->
|
||||
@get('hasPermission')
|
||||
).property('hasPermission')
|
||||
|
||||
`export default RepoShowToolsComponent`
|
|
@ -1,38 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import config from 'travis/config/environment';
|
||||
import { hasPermission, hasPushPermission } from 'travis/utils/permission';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
popup: Ember.inject.service(),
|
||||
classNames: ['option-button'],
|
||||
classNameBindings: ['isOpen:display'],
|
||||
isOpen: false,
|
||||
|
||||
click(event) {
|
||||
if ($(event.target).is('a') && $(event.target).parents('.settings-dropdown').length) {
|
||||
return this.closeMenu();
|
||||
}
|
||||
},
|
||||
|
||||
closeMenu() {
|
||||
return this.toggleProperty('isOpen');
|
||||
},
|
||||
|
||||
actions: {
|
||||
menu() {
|
||||
return this.toggleProperty('isOpen');
|
||||
}
|
||||
},
|
||||
displaySettingsLink: function() {
|
||||
return hasPushPermission(this.get('currentUser'), this.get('repo.id'));
|
||||
}.property('currentUser.pushPermissions.length', 'repo'),
|
||||
|
||||
displayCachesLink: function() {
|
||||
return hasPushPermission(this.get('currentUser'), this.get('repo.id')) && config.endpoints.caches;
|
||||
}.property('currentUser.pushPermissions.length', 'repo'),
|
||||
|
||||
displayStatusImages: function() {
|
||||
return hasPermission(this.get('currentUser'), this.get('repo.id'));
|
||||
}.property('currentUser.permissions.length', 'repo.id')
|
||||
|
||||
});
|
|
@ -1,7 +0,0 @@
|
|||
import Polling from 'travis/mixins/polling';
|
||||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend(Polling, {
|
||||
pollModels: 'repo',
|
||||
classNameBindings: ['isLoading:loading']
|
||||
});
|
5
app/components/repos-empty.coffee
Normal file
5
app/components/repos-empty.coffee
Normal file
|
@ -0,0 +1,5 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
ReposEmptyComponent = Ember.Component.extend()
|
||||
|
||||
`export default ReposEmptyComponent`
|
|
@ -1,3 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend();
|
31
app/components/repos-list-item.coffee
Normal file
31
app/components/repos-list-item.coffee
Normal file
|
@ -0,0 +1,31 @@
|
|||
`import Ember from 'ember'`
|
||||
`import Polling from 'travis/mixins/polling'`
|
||||
`import { colorForState } from 'travis/utils/helpers'`
|
||||
|
||||
ReposListItemComponent = Ember.Component.extend Polling,
|
||||
routing: Ember.inject.service('-routing')
|
||||
|
||||
tagName: 'li'
|
||||
|
||||
pollModels: 'repo'
|
||||
|
||||
classNames: ['repo']
|
||||
classNameBindings: ['selected']
|
||||
selected: (->
|
||||
@get('repo') == @get('selectedRepo')
|
||||
).property('selectedRepo')
|
||||
|
||||
color: (->
|
||||
colorForState(@get('repo.lastBuildState'))
|
||||
).property('repo.lastBuildState')
|
||||
|
||||
scrollTop: (->
|
||||
if (window.scrollY > 0)
|
||||
$('html, body').animate({scrollTop: 0}, 200)
|
||||
)
|
||||
|
||||
click: ->
|
||||
@scrollTop()
|
||||
@get('routing').transitionTo('repo', @get('repo.slug').split('/'))
|
||||
|
||||
`export default ReposListItemComponent`
|
|
@ -1,27 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import Polling from 'travis/mixins/polling';
|
||||
import { colorForState } from 'travis/utils/helpers';
|
||||
|
||||
export default Ember.Component.extend(Polling, {
|
||||
routing: Ember.inject.service('-routing'),
|
||||
tagName: 'li',
|
||||
pollModels: 'repo',
|
||||
classNames: ['repo'],
|
||||
classNameBindings: ['selected'],
|
||||
|
||||
selected: function() {
|
||||
return this.get('repo') === this.get('selectedRepo');
|
||||
}.property('selectedRepo'),
|
||||
|
||||
color: function() {
|
||||
return colorForState(this.get('repo.lastBuildState'));
|
||||
}.property('repo.lastBuildState'),
|
||||
|
||||
scrollTop: function() {
|
||||
if (window.scrollY > 0) {
|
||||
return $('html, body').animate({
|
||||
scrollTop: 0
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
});
|
|
@ -1,48 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
auth: Ember.inject.service(),
|
||||
|
||||
currentUserBinding: 'auth.currentUser',
|
||||
|
||||
classRecent: function() {
|
||||
if (this.get('tab') === 'recent') {
|
||||
return 'active';
|
||||
} else if (this.get('tab') === 'search' && this.get('auth.signedIn')) {
|
||||
return 'hidden';
|
||||
}
|
||||
}.property('tab'),
|
||||
|
||||
classRunning: function() {
|
||||
var classes;
|
||||
classes = [];
|
||||
if (this.get('tab') === 'running') {
|
||||
classes.push('active');
|
||||
}
|
||||
return classes.join(' ');
|
||||
}.property('tab'),
|
||||
|
||||
classOwned: function() {
|
||||
var classes;
|
||||
classes = [];
|
||||
if (this.get('tab') === 'owned') {
|
||||
classes.push('active');
|
||||
}
|
||||
if (this.get('currentUser')) {
|
||||
classes.push('display-inline');
|
||||
}
|
||||
return classes.join(' ');
|
||||
}.property('tab', 'currentUser'),
|
||||
|
||||
classSearch: function() {
|
||||
if (this.get('tab') === 'search') {
|
||||
return 'active';
|
||||
}
|
||||
}.property('tab'),
|
||||
|
||||
classNew: function() {
|
||||
if (this.get('currentUser')) {
|
||||
return 'display-inline';
|
||||
}
|
||||
}.property('currentUser')
|
||||
});
|
25
app/components/request-icon.coffee
Normal file
25
app/components/request-icon.coffee
Normal file
|
@ -0,0 +1,25 @@
|
|||
`import Ember from 'ember'`
|
||||
|
||||
RequestIconComponent = Ember.Component.extend
|
||||
|
||||
tagName: 'span'
|
||||
classNames: ['status-icon', 'icon']
|
||||
classNameBindings: ['event', 'state']
|
||||
|
||||
isPush: (->
|
||||
@get('event') == 'push'
|
||||
).property('event')
|
||||
|
||||
isPR: (->
|
||||
@get('event') == 'pull_request'
|
||||
).property('event')
|
||||
|
||||
isAPI: (->
|
||||
@get('event') == 'api'
|
||||
).property('event')
|
||||
|
||||
isEmpty: (->
|
||||
true if @get('event') == null || @get('event') == null
|
||||
).property('event')
|
||||
|
||||
`export default RequestIconComponent`
|
|
@ -1,25 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'span',
|
||||
classNames: ['request-icon', 'icon'],
|
||||
classNameBindings: ['event', 'state'],
|
||||
|
||||
isPush: function() {
|
||||
return this.get('event') === 'push';
|
||||
}.property('event'),
|
||||
|
||||
isPR: function() {
|
||||
return this.get('event') === 'pull_request';
|
||||
}.property('event'),
|
||||
|
||||
isAPI: function() {
|
||||
return this.get('event') === 'api';
|
||||
}.property('event'),
|
||||
|
||||
isEmpty: function() {
|
||||
if (this.get('event') === null || this.get('event') === null) {
|
||||
return true;
|
||||
}
|
||||
}.property('event')
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user