mirror of https://github.com/rancher/ui.git
Projects WIP
This commit is contained in:
parent
d6ae030828
commit
82d4b86456
|
|
@ -42,6 +42,7 @@ export default Ember.Route.extend({
|
|||
|
||||
error: function(err) {
|
||||
this.controllerFor('application').set('error',err);
|
||||
this.set('app.showArticles',false);
|
||||
this.transitionTo('failWhale');
|
||||
console.log('Application ' + err.stack);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -13,11 +13,17 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
|
|||
var session = this.get('session');
|
||||
|
||||
// Load schemas
|
||||
return store.find('schema', null, {url: 'schemas'}).then((schemas) => {
|
||||
session.set(C.SESSION.ACCOUNT_ID, schemas.xhr.getResponseHeader(C.HEADER.ACCOUNT_ID));
|
||||
var headers = {};
|
||||
headers[C.HEADER.PROJECT] = C.HEADER.PROJECT_USER_SCOPE;
|
||||
return store.find('schema', null, {url: 'schemas', headers: headers}).then((schemas) => {
|
||||
if ( schemas && schemas.xhr )
|
||||
{
|
||||
// Save the account ID into session
|
||||
session.set(C.SESSION.ACCOUNT_ID, schemas.xhr.getResponseHeader(C.HEADER.ACCOUNT_ID));
|
||||
}
|
||||
|
||||
var type = session.get(C.SESSION.USER_TYPE);
|
||||
var isAdmin = (type === C.USER.TYPE_ADMIN) || (!type && store.hasRecordFor('schema','githubconfig'));
|
||||
var isAdmin = (type === C.USER.TYPE_ADMIN) || (!this.get('app.authenticationEnabled'));
|
||||
this.set('app.isAuthenticationAdmin', isAdmin);
|
||||
|
||||
return store.find('project', null, {forceReload: true});
|
||||
|
|
@ -40,7 +46,12 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
|
|||
var active = ActiveArrayProxy.create({sourceContent: model});
|
||||
controller.set('projects', active);
|
||||
|
||||
this.selectDefaultProject(controller);
|
||||
},
|
||||
|
||||
selectDefaultProject: function(controller) {
|
||||
var session = this.get('session');
|
||||
var active = controller.get('projects');
|
||||
|
||||
// Figure out the active project
|
||||
var project = null;
|
||||
|
|
@ -77,8 +88,7 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
|
|||
else
|
||||
{
|
||||
// @TODO Then cry? What happens if you delete the last project?
|
||||
session.set(C.SESSION.PROJECT, undefined);
|
||||
controller.set('project', null);
|
||||
this.send('logout');
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -97,18 +107,28 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
|
|||
}
|
||||
},
|
||||
|
||||
selectDefaultProject: function() {
|
||||
return this.selectDefaultProject(this.get('controller'));
|
||||
},
|
||||
|
||||
refreshProjectDropdown: function() {
|
||||
this.get('store').find('project', null, {forceReload: true}).then((res) => {
|
||||
this.set('controller.projects.sourceContent', res);
|
||||
this.selectDefaultProject(this.get('controller'));
|
||||
});
|
||||
},
|
||||
|
||||
switchProject: function(projectId) {
|
||||
switchProject: function(projectId,route) {
|
||||
this.get('session').set(C.SESSION.PROJECT, projectId);
|
||||
this.get('store').reset();
|
||||
this.transitionTo('index');
|
||||
if ( !projectId )
|
||||
{
|
||||
this.selectDefaultProject();
|
||||
}
|
||||
this.transitionTo(route||'index');
|
||||
},
|
||||
|
||||
|
||||
setPageLayout: function(opt) {
|
||||
this.controller.set('pageName', opt.label || '');
|
||||
this.controller.set('backRoute', opt.backRoute || null);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import Ember from 'ember';
|
||||
import GithubUserInfoMixin from 'ui/mixins/github-user-info';
|
||||
import GithubInfoMixin from 'ui/mixins/github-info';
|
||||
|
||||
export default Ember.Component.extend(GithubUserInfoMixin,{
|
||||
export default Ember.Component.extend(GithubInfoMixin,{
|
||||
classNames: ['gh-avatar'],
|
||||
link: true,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
import Ember from 'ember';
|
||||
import GithubUserInfoMixin from 'ui/mixins/github-user-info';
|
||||
import GithubInfoMixin from 'ui/mixins/github-info';
|
||||
|
||||
export default Ember.Component.extend(GithubUserInfoMixin,{
|
||||
export default Ember.Component.extend(GithubInfoMixin,{
|
||||
classNames: ['gh-block'],
|
||||
avatar: true,
|
||||
link: true,
|
||||
|
||||
isTeam: Ember.computed.equal('type','team'),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -33,10 +33,18 @@
|
|||
{{/if}}
|
||||
</div>
|
||||
<div class="gh-block-detail clip">
|
||||
{{#if description}}
|
||||
{{description}}
|
||||
{{#if isTeam}}
|
||||
{{#if org}}
|
||||
Team in <a {{bind-attr href=orgUrl}} target="_blank">{{org}}</a> org
|
||||
{{else}}
|
||||
You are not a member of this team.
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<i>No Name</i>
|
||||
{{#if description}}
|
||||
{{description}}
|
||||
{{else}}
|
||||
<i>No Name</i>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
allowTeams: true,
|
||||
|
||||
checking: false,
|
||||
addInput: '',
|
||||
|
||||
actions: {
|
||||
add: function() {
|
||||
if ( this.get('checking') )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.set('checking', true);
|
||||
var input = this.get('addInput').trim();
|
||||
|
||||
this.get('github').find('user_or_org', input).then((info) => {
|
||||
this.set('addInput','');
|
||||
this.send('addObject', info);
|
||||
}).catch(() => {
|
||||
this.sendAction('onError','Unable to find: ' + input);
|
||||
}).finally(() => {
|
||||
this.set('checking', false);
|
||||
});
|
||||
},
|
||||
|
||||
addObject: function(info) {
|
||||
this.sendAction('action', Ember.Object.create({
|
||||
id: info.get('id'),
|
||||
type: info.get('type'),
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
addDisabled: function() {
|
||||
return this.get('checking') || this.get('addInput').trim().length === 0;
|
||||
}.property('addInput','checking'),
|
||||
|
||||
orgChoices: function() {
|
||||
var orgs = (this.get('session.orgs')||[]).slice().sort().map(function(id) {
|
||||
return Ember.Object.create({
|
||||
id: id,
|
||||
type: 'org',
|
||||
teams: []
|
||||
});
|
||||
});
|
||||
|
||||
(this.get('session.teams')||[]).forEach(function(team) {
|
||||
var org = orgs.filterProperty('id', team.org)[0];
|
||||
if ( org )
|
||||
{
|
||||
org.teams.pushObject(Ember.Object.create({
|
||||
id: team.id,
|
||||
type: 'team',
|
||||
name: team.name,
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
return orgs;
|
||||
}.property('session.orgs.[]','session.teams.@each.id'),
|
||||
});
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<form {{action "add" on="submit"}}>
|
||||
<div class="input-group">
|
||||
{{input type="text" value=addInput placeholder="Add a GitHub user or organization name" class="form-control"}}
|
||||
<div class="input-group-btn">
|
||||
{{#if checking}}
|
||||
<button class="btn btn-primary btn-disabled"><i class="fa fa-circle-o-notch fa-spin"></i></button>
|
||||
{{else}}
|
||||
<button class="btn btn-primary" {{action "add"}}><i class="ss-plus"></i></button>
|
||||
{{/if}}
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><span class="caret"></span></button>
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu" style="min-width: 250px; max-height: 300px; overflow-y: auto;">
|
||||
<li role="presentation" class="dropdown-header">Your Organizations and Teams</li>
|
||||
{{#each item in orgChoices}}
|
||||
<li>
|
||||
<a {{action "addObject" item}}>
|
||||
{{github-block login=item.id link=false}}
|
||||
</a>
|
||||
</li>
|
||||
{{#if allowTeams}}
|
||||
{{#each team in item.teams}}
|
||||
<li style="margin-left: 15px;">
|
||||
<a {{action "addObject" team}}>
|
||||
<i class="ss-users"></i> {{team.name}}
|
||||
</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -11,7 +11,8 @@ export default Ember.Component.extend({
|
|||
},
|
||||
|
||||
showAccessWarning: function() {
|
||||
return !this.get('app.authenticationEnabled') &&
|
||||
return this.get('app.showArticles') !== false &&
|
||||
!this.get('app.authenticationEnabled') &&
|
||||
this.get('prefs.'+C.ACCESS_WARNING) !== false;
|
||||
}.property('app.authenticationEnabled','prefs.'+C.ACCESS_WARNING)
|
||||
});
|
||||
|
|
|
|||
|
|
@ -49,8 +49,9 @@
|
|||
</div>
|
||||
|
||||
<div class="right" style="padding-right: 0;">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-link dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||
<div class="btn-group project-btn">
|
||||
<div class="text-muted">Project:</div>
|
||||
<button type="button" class="btn btn-link dropdown-toggle clip" data-toggle="dropdown" aria-expanded="false">
|
||||
{{#if project}}
|
||||
{{#with project as p controller="project"}}
|
||||
<i {{bind-attr class=":fa-fw p.icon"}}></i> {{p.displayName}}
|
||||
|
|
@ -59,18 +60,18 @@
|
|||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu">
|
||||
<li role="presentation" class="dropdown-header">Available Projects:</li>
|
||||
<li>{{#link-to "projects"}}Manage Projects{{/link-to}}</li>
|
||||
<li role="presentation" class="divider"></li>
|
||||
<li role="presentation" class="dropdown-header">Your Projects:</li>
|
||||
{{#each p in projectChoices itemController="project"}}
|
||||
<li {{bind-attr class="p.active:disabled p.active:selected"}}>
|
||||
<a {{action "switchProject" p.id}}>
|
||||
<i {{bind-attr class=":fa-fw p.listIcon"}}></i>
|
||||
<a {{action "switchProject" p.id}} class="clip">
|
||||
<i {{bind-attr class=":fa-fw p.icon"}}></i>
|
||||
|
||||
{{p.displayName}}
|
||||
</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
<li role="presentation" class="divider"></li>
|
||||
<li>{{#link-to "projects"}}Manage Projects{{/link-to}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
import Github from 'ui/utils/github';
|
||||
|
||||
export function initialize(container, application) {
|
||||
var github = Github.create({
|
||||
// Session isn't automatically injected into GitHub
|
||||
session: container.lookup('session:main'),
|
||||
});
|
||||
|
||||
// Inject GitHub lookup as 'github' property
|
||||
container.register('github:main', github, {instantiate: false});
|
||||
application.inject('controller', 'github', 'github:main');
|
||||
application.inject('component', 'github', 'github:main');
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'github',
|
||||
after: 'session',
|
||||
initialize: initialize
|
||||
};
|
||||
|
|
@ -19,12 +19,17 @@ export function initialize(container, application) {
|
|||
// Please don't send us www-authenticate headers
|
||||
out[C.HEADER.NO_CHALLENGE] = C.HEADER.NO_CHALLENGE_VALUE;
|
||||
|
||||
// Send the token as the Authorization header
|
||||
var authValue = session.get(C.SESSION.TOKEN);
|
||||
if ( authValue )
|
||||
{
|
||||
// Send the token as the Authorization header if present
|
||||
out[C.HEADER.AUTH] = C.HEADER.AUTH_TYPE + ' ' + authValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// And something else if not present, so the browser can't send cached basic creds
|
||||
out[C.HEADER.AUTH] = 'None';
|
||||
}
|
||||
|
||||
// Send the current project id as a header if in a project
|
||||
var projectId = session.get(C.SESSION.PROJECT);
|
||||
|
|
|
|||
|
|
@ -58,7 +58,14 @@ export default Ember.Controller.extend({
|
|||
},
|
||||
}).then(function(res) {
|
||||
var auth = JSON.parse(res.xhr.responseText);
|
||||
session.setProperties(auth);
|
||||
var interesting = {};
|
||||
C.TOKEN_TO_SESSION_KEYS.forEach((key) => {
|
||||
if ( typeof auth[key] !== 'undefined' )
|
||||
{
|
||||
interesting[key] = auth[key];
|
||||
}
|
||||
});
|
||||
session.setProperties(interesting);
|
||||
session.set(C.LOGGED_IN, true);
|
||||
var transition = app.get('afterLoginTransition');
|
||||
if ( transition )
|
||||
|
|
|
|||
|
|
@ -2,49 +2,16 @@ import Ember from 'ember';
|
|||
import C from 'ui/utils/constants';
|
||||
import Cattle from 'ui/utils/cattle';
|
||||
import Util from 'ui/utils/util';
|
||||
import GithubLookup from 'ui/utils/github-lookup';
|
||||
|
||||
export default Ember.Mixin.create(Cattle.NewOrEditMixin, {
|
||||
githubLookup: null,
|
||||
isAdding: false,
|
||||
addMemberInput: null,
|
||||
|
||||
actions: {
|
||||
addMember: function(item) {
|
||||
if ( item && typeof item === 'object' )
|
||||
{
|
||||
this.send('maybeAddMember', Ember.Object.create({
|
||||
externalId: item.get('id'),
|
||||
externalIdType: item.get('type'),
|
||||
role: C.PROJECT.ROLE_MEMBER,
|
||||
}));
|
||||
}
|
||||
else if ( item && item.length )
|
||||
{
|
||||
var lookup = this.get('githubLookup');
|
||||
if ( !lookup )
|
||||
{
|
||||
lookup = GithubLookup.create();
|
||||
this.set('githubLookup', lookup);
|
||||
}
|
||||
checkMember: function(obj) {
|
||||
var member = Ember.Object.create({
|
||||
externalId: obj.get('id'),
|
||||
externalIdType: C.PROJECT.FROM_GITHUB[ obj.get('type') ],
|
||||
role: C.PROJECT.ROLE_MEMBER
|
||||
});
|
||||
|
||||
this.set('isAdding', true);
|
||||
lookup.find('user', item).then((info) => {
|
||||
this.set('addMemberInput','');
|
||||
this.send('maybeAddMember', Ember.Object.create({
|
||||
externalId: info.get('id'),
|
||||
externalIdType: (info.get('type') === 'user' ? C.PROJECT.TYPE_USER : C.PROJECT.TYPE_ORG),
|
||||
role: C.PROJECT.ROLE_MEMBER,
|
||||
}));
|
||||
}).catch(() => {
|
||||
this.send('error','Unable to find user/org: ' + item);
|
||||
}).finally(() => {
|
||||
this.set('isAdding', false);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
maybeAddMember: function(member) {
|
||||
var existing = this.get('members')
|
||||
.filterProperty('externalIdType', member.get('externalIdType'))
|
||||
.filterProperty('externalId', member.get('externalId'));
|
||||
|
|
@ -73,30 +40,6 @@ export default Ember.Mixin.create(Cattle.NewOrEditMixin, {
|
|||
});
|
||||
}.property(),
|
||||
|
||||
orgChoices: function() {
|
||||
var orgs = this.get('session.orgs').slice().sort().map(function(id) {
|
||||
return Ember.Object.create({
|
||||
id: id,
|
||||
type: C.PROJECT.TYPE_ORG,
|
||||
teams: []
|
||||
});
|
||||
});
|
||||
|
||||
this.get('session.teams').forEach(function(team) {
|
||||
var org = orgs.filterProperty('id', team.org)[0];
|
||||
if ( org )
|
||||
{
|
||||
org.teams.pushObject(Ember.Object.create({
|
||||
id: team.id,
|
||||
type: C.PROJECT.TYPE_TEAM,
|
||||
name: team.name,
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
return orgs;
|
||||
}.property('session.orgs.[]','session.teams.[]'),
|
||||
|
||||
hasOwner: function() {
|
||||
return this.get('members').filterProperty('role', C.PROJECT.ROLE_OWNER).get('length') > 0;
|
||||
}.property('members.@each.role'),
|
||||
|
|
@ -107,7 +50,7 @@ export default Ember.Mixin.create(Cattle.NewOrEditMixin, {
|
|||
|
||||
if ( !this.get('hasOwner') )
|
||||
{
|
||||
errors.push('A project must have at least one owner');
|
||||
errors.push('You must add at least one owner');
|
||||
}
|
||||
|
||||
if ( errors.length )
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
import Ember from 'ember';
|
||||
import C from 'ui/utils/constants';
|
||||
import Util from 'ui/utils/util';
|
||||
|
||||
export default Ember.Mixin.create({
|
||||
type: 'user_or_org',
|
||||
login: null, // This can't be called id because Ember uses that property..
|
||||
size: 40,
|
||||
fallback: null,
|
||||
|
||||
name: null,
|
||||
description: 'Loading...',
|
||||
org: null,
|
||||
|
||||
_avatarUrl: null,
|
||||
|
||||
|
||||
isTeam: Ember.computed.equal('type','team'),
|
||||
|
||||
loginOrTypeChanged: function() {
|
||||
var login = this.get('login');
|
||||
var type = this.get('type');
|
||||
var fallback = this.get('fallback');
|
||||
|
||||
if ( !type || !login )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.setProperties({
|
||||
'name': login,
|
||||
'description': 'Loading...',
|
||||
'_avatarUrl': null,
|
||||
});
|
||||
|
||||
this.get('github').find(type, login).then((entry) => {
|
||||
this.setProperties({
|
||||
name: entry.name,
|
||||
description: entry.description,
|
||||
_avatarUrl: entry.avatarUrl,
|
||||
org: entry.org,
|
||||
});
|
||||
}).catch((err) => {
|
||||
if ( fallback && this.get('type') === 'team' )
|
||||
{
|
||||
this.setProperties({
|
||||
name: "(A team you don't have access to)",
|
||||
org: fallback,
|
||||
_avatarUrl: null
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.setProperties({
|
||||
name: login,
|
||||
description: 'Error: ' + err,
|
||||
org: null,
|
||||
_avatarUrl: null
|
||||
});
|
||||
}
|
||||
});
|
||||
}.observes('login','type','fallback').on('init'),
|
||||
|
||||
avatarUrl: function(){
|
||||
var url = this.get('_avatarUrl');
|
||||
if ( url )
|
||||
{
|
||||
url = Util.addQueryParam(url, 's', this.get('size'));
|
||||
}
|
||||
return url;
|
||||
}.property('_avatarUrl','size'),
|
||||
|
||||
orgUrl: function() {
|
||||
var org = this.get('org');
|
||||
if ( org && this.get('type') === 'team' )
|
||||
{
|
||||
return C.GITHUB.URL + 'orgs/' + encodeURIComponent(org);
|
||||
}
|
||||
}.property('type','org'),
|
||||
|
||||
url: function() {
|
||||
if ( this.get('type') === 'team' )
|
||||
{
|
||||
var entry = this.get('github').teamById(this.get('login'));
|
||||
if ( entry && entry.slug )
|
||||
{
|
||||
return C.GITHUB.URL + 'orgs/' + encodeURIComponent(entry.org) + '/teams/' + encodeURIComponent(entry.slug);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return C.GITHUB.URL + encodeURIComponent(this.get('login'));
|
||||
}
|
||||
}.property('login'),
|
||||
});
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
import C from 'ui/utils/constants';
|
||||
import Util from 'ui/utils/util';
|
||||
|
||||
export default Ember.Mixin.create({
|
||||
type: 'user',
|
||||
login: null,
|
||||
size: 40,
|
||||
|
||||
name: null,
|
||||
description: 'Loading...',
|
||||
_avatarUrl: null,
|
||||
|
||||
loginOrTypeChanged: function() {
|
||||
var self = this;
|
||||
var session = this.get('session');
|
||||
|
||||
var cache = session.get('githubCache')||{};
|
||||
var login = this.get('login');
|
||||
var type = this.get('type');
|
||||
var key = type + ':' + login;
|
||||
|
||||
if ( !type || !login )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Teams can't be looked up without auth...
|
||||
if ( type === 'team' )
|
||||
{
|
||||
var entry = (session.get('teams')||[]).filterProperty('id', login)[0];
|
||||
this.set('_avatarUrl', null);
|
||||
if ( entry )
|
||||
{
|
||||
this.set('name', entry.name);
|
||||
this.set('description', entry.org + ' team');
|
||||
}
|
||||
else
|
||||
{
|
||||
this.set('name', '('+ login + ')');
|
||||
this.set('description', '(Unknown team id)');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.set('name', login);
|
||||
|
||||
|
||||
if ( cache[key] )
|
||||
{
|
||||
gotInfo(cache[key]);
|
||||
}
|
||||
else
|
||||
{
|
||||
var url = C.GITHUB.PROXY_URL + type + 's/' + login;
|
||||
this.request(url).then((body) => {
|
||||
cache[key] = body;
|
||||
|
||||
// Sub-keys don't get automatically persisted to the session...
|
||||
session.set('githubCache', cache);
|
||||
|
||||
gotInfo(body);
|
||||
}, (/*err*/) => {
|
||||
this.sendAction('notFound', login);
|
||||
});
|
||||
}
|
||||
|
||||
function gotInfo(body)
|
||||
{
|
||||
self.set('description', body.name);
|
||||
self.set('_avatarUrl', body.avatar_url);
|
||||
}
|
||||
}.observes('login','type').on('init'),
|
||||
|
||||
avatarUrl: function(){
|
||||
var url = this.get('_avatarUrl');
|
||||
if ( url )
|
||||
{
|
||||
url = Util.addQueryParam(url, 's', this.get('size'));
|
||||
}
|
||||
return url;
|
||||
}.property('_avatarUrl','size'),
|
||||
|
||||
url: function() {
|
||||
if ( this.get('type') === 'team' )
|
||||
{
|
||||
var entry = (this.get('session.teams')||[]).filterProperty('id', this.get('login'))[0];
|
||||
if ( entry && entry.slug )
|
||||
{
|
||||
return C.GITHUB.URL + 'orgs/' + encodeURIComponent(entry.org) + '/teams/' + encodeURIComponent(entry.slug);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return C.GITHUB.URL + encodeURIComponent(this.get('login'));
|
||||
}
|
||||
}.property('login'),
|
||||
|
||||
request: function(url) {
|
||||
var headers = {};
|
||||
|
||||
var authValue = this.get('session').get(C.SESSION.TOKEN);
|
||||
if ( authValue )
|
||||
{
|
||||
headers[C.HEADER.AUTH] = C.HEADER.AUTH_TYPE + ' ' + authValue;
|
||||
}
|
||||
|
||||
return Ember.$.ajax({url: url, headers: headers, dataType: 'json'});
|
||||
},
|
||||
});
|
||||
|
|
@ -11,9 +11,9 @@ var ProjectController = Cattle.TransitioningResourceController.extend({
|
|||
delete: function() {
|
||||
return this.delete().then(() => {
|
||||
// If you're in the project that was deleted, go back to the default project
|
||||
if ( this.get('id') === this.get('session.projectId') )
|
||||
if ( this.get('id') === this.get('session.'+ C.SESSION.PROJECT) )
|
||||
{
|
||||
this.send('switchProject', undefined);
|
||||
window.location.href = window.location.href;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
@ -23,7 +23,12 @@ var ProjectController = Cattle.TransitioningResourceController.extend({
|
|||
},
|
||||
|
||||
deactivate: function() {
|
||||
return this.doAction('deactivate');
|
||||
return this.doAction('deactivate').then(() => {
|
||||
if ( this.get('id') === this.get('session.'+ C.SESSION.PROJECT) )
|
||||
{
|
||||
window.location.href = window.location.href;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
switchTo: function() {
|
||||
|
|
@ -36,7 +41,11 @@ var ProjectController = Cattle.TransitioningResourceController.extend({
|
|||
isOrg: Ember.computed.equal('externalIdType', C.PROJECT.TYPE_ORG),
|
||||
|
||||
icon: function() {
|
||||
if ( this.get('active') )
|
||||
if ( this.get('isDefault') )
|
||||
{
|
||||
return 'ss-home';
|
||||
}
|
||||
else if ( this.get('active') )
|
||||
{
|
||||
return 'ss-openfolder';
|
||||
}
|
||||
|
|
@ -44,22 +53,15 @@ var ProjectController = Cattle.TransitioningResourceController.extend({
|
|||
{
|
||||
return 'ss-folder';
|
||||
}
|
||||
}.property('active'),
|
||||
}.property('active','isDefault'),
|
||||
|
||||
listIcon: function() {
|
||||
if ( this.get('active') )
|
||||
{
|
||||
return 'ss-check';
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.get('icon');
|
||||
}
|
||||
}.property('icon','active'),
|
||||
isDefault: function() {
|
||||
return this.get('session.' + C.SESSION.PROJECT_DEFAULT) === this.get('id');
|
||||
}.property('session.' + C.SESSION.PROJECT_DEFAULT, 'id'),
|
||||
|
||||
active: function() {
|
||||
return this.get('session.projectId') === this.get('id');
|
||||
}.property('session.projectId','id'),
|
||||
return this.get('session.' + C.SESSION.PROJECT) === this.get('id');
|
||||
}.property('session' + C.SESSION.PROJECT, 'id'),
|
||||
|
||||
canRemove: function() {
|
||||
return !!this.get('actions.remove') && ['removing','removed','purging','purged'].indexOf(this.get('state')) === -1;
|
||||
|
|
@ -75,14 +77,10 @@ var ProjectController = Cattle.TransitioningResourceController.extend({
|
|||
{ divider: true },
|
||||
{ label: 'Restore', icon: '', action: 'restore', enabled: !!a.restore },
|
||||
{ label: 'Purge', icon: '', action: 'purge', enabled: !!a.purge },
|
||||
{ divider: true },
|
||||
{ label: 'Edit', icon: '', action: 'edit', enabled: !!a.update },
|
||||
];
|
||||
|
||||
if ( this.get('app.isAuthenticationAdmin') )
|
||||
{
|
||||
choices.pushObject({label: 'Switch to Project', icon: 'ss-openfolder', action: 'switchTo', enabled: this.get('state') === 'active' });
|
||||
}
|
||||
choices.pushObject({label: 'Switch to this Project', icon: '', action: 'switchTo', enabled: this.get('state') === 'active' });
|
||||
|
||||
return choices;
|
||||
}.property('actions.{activate,deactivate,update,restore,purge}','canRemove'),
|
||||
|
|
|
|||
|
|
@ -4,4 +4,11 @@ export default Ember.Route.extend({
|
|||
model: function(params /*, transition*/) {
|
||||
return this.get('store').find('project', params.project_id);
|
||||
},
|
||||
|
||||
actions: {
|
||||
didTransition: function() {
|
||||
this._super();
|
||||
this.send('setPageLayout', {label: 'All Projects', backRoute: 'projects'});
|
||||
},
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,13 +7,17 @@ export default Ember.ObjectController.extend({
|
|||
isTeam: Ember.computed.equal('externalIdType', C.PROJECT.TYPE_TEAM),
|
||||
isOrg: Ember.computed.equal('externalIdType', C.PROJECT.TYPE_ORG),
|
||||
|
||||
isMyRancher: function() {
|
||||
return this.get('externalIdType') === C.PROJECT.TYPE_RANCHER && this.get('externalId') === this.get('session').get(C.SESSION.ACCOUNT_ID);
|
||||
}.property('externalId','externalIdType'),
|
||||
|
||||
githubType: function() {
|
||||
switch ( this.get('externalIdType') )
|
||||
{
|
||||
case C.PROJECT.TYPE_USER: return 'user';
|
||||
case C.PROJECT.TYPE_TEAM: return 'team';
|
||||
case C.PROJECT.TYPE_ORG: return 'org';
|
||||
case C.PROJECT.TYPE_RANCHER: return '';
|
||||
case C.PROJECT.TYPE_RANCHER: return null;
|
||||
}
|
||||
}.property('type'),
|
||||
|
||||
|
|
|
|||
|
|
@ -22,44 +22,20 @@
|
|||
|
||||
{{partial "form-divider"}}
|
||||
|
||||
{{#if app.authenticationEnabled}}
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-2 form-label">
|
||||
<label>Members</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-8">
|
||||
<form {{action "addMember" on="submit"}}>
|
||||
<div class="input-group">
|
||||
{{input type="text" value=addMemberInput placeholder="Add a GitHub user or organization name" class="form-control"}}
|
||||
<div class="input-group-btn">
|
||||
{{#if isAdding}}
|
||||
<button class="btn btn-primary btn-disabled"><i class="ss-loading fa-spin"></i></button>
|
||||
{{else}}
|
||||
<button class="btn btn-primary" {{action "addMember" addMemberInput}}><i class="ss-plus"></i></button>
|
||||
{{/if}}
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><span class="caret"></span></button>
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu" style="min-width: 250px; max-height: 300px; overflow-y: auto;">
|
||||
<li role="presentation" class="dropdown-header">Your Organizations and Teams</li>
|
||||
{{#each item in orgChoices}}
|
||||
<li>
|
||||
<a {{action "addMember" item}}>
|
||||
{{github-block type="org" login=item.id link=false}}
|
||||
</a>
|
||||
</li>
|
||||
{{#each team in item.teams}}
|
||||
<li style="margin-left: 15px;">
|
||||
<a {{action "addMember" team}}>
|
||||
<i class="ss-users"></i> {{team.name}}
|
||||
</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<div class="col-sm-12 col-md-2 form-label">
|
||||
<label>Members</label>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-8">
|
||||
{{#if app.authenticationEnabled}}
|
||||
{{input-github action="checkMember" onError="error"}}
|
||||
{{else}}
|
||||
<p class="help-block">Access Control is not enabled. Everybody is Admin and will be able to use this project.</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if app.authenticationEnabled}}
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-8 col-md-offset-2">
|
||||
{{#if members.length}}
|
||||
|
|
@ -76,25 +52,43 @@
|
|||
{{#each member in members itemController="projectmember"}}
|
||||
<tr>
|
||||
<td>
|
||||
{{github-block type=member.githubType login=member.externalId}}
|
||||
{{#if member.isRancher}}
|
||||
{{#if member.isMyRancher}}
|
||||
My Rancher Account
|
||||
{{else}}
|
||||
Rancher Account: {{member.name}} ({{member.externalId}})
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{github-block type=member.githubType login=member.externalId fallback=member.name}}
|
||||
{{/if}}
|
||||
</td>
|
||||
<td>{{member.displayType}}</td>
|
||||
<td>
|
||||
{{view "select"
|
||||
class="form-control input-sm"
|
||||
content=roleOptions
|
||||
value=member.role
|
||||
optionValuePath="content.value"
|
||||
optionLabelPath="content.label"
|
||||
}}
|
||||
{{#if member.isRancher}}
|
||||
{{uc-first member.role}}
|
||||
{{else}}
|
||||
{{view "select"
|
||||
class="form-control input-sm"
|
||||
content=roleOptions
|
||||
value=member.role
|
||||
optionValuePath="content.value"
|
||||
optionLabelPath="content.label"
|
||||
}}
|
||||
{{/if}}
|
||||
</td>
|
||||
<td>
|
||||
{{#if app.authenticationEnabled}}
|
||||
<button class="btn-circle-x btn-sm pull-right gh-action" {{action "removeMember" member}}></button>
|
||||
{{else}}
|
||||
|
||||
{{/if}}
|
||||
</td>
|
||||
<td><button class="btn-circle-x btn-sm pull-right gh-action" {{action "removeMember" member}}></button></td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<div class="text-muted">No members.</div>
|
||||
<div class="text-muted">No members yet, add at least one owner.</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import Ember from 'ember';
|
|||
export default Ember.View.extend({
|
||||
didInsertElement: function() {
|
||||
$('BODY').addClass('white');
|
||||
this.$('INPUT')[0].focus();
|
||||
this._super();
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
<ul class="list-unstyled gh-block-list">
|
||||
{{#each user in allowedUsers}}
|
||||
<li>
|
||||
{{#github-block type="user" login=user notFound="userNotFound"}}
|
||||
{{#github-block login=user notFound="userNotFound"}}
|
||||
<button class="btn-circle-x btn-sm pull-right gh-action" {{action "removeUser" user}}></button>
|
||||
{{/github-block}}
|
||||
</li>
|
||||
|
|
@ -88,7 +88,7 @@
|
|||
<ul class="list-unstyled gh-block-list">
|
||||
{{#each org in allowedOrganizations}}
|
||||
<li>
|
||||
{{#github-block type="org" login=org notFound="orgNotFound"}}
|
||||
{{#github-block login=org notFound="orgNotFound"}}
|
||||
<button class="btn-circle-x btn-sm pull-right gh-action" {{action "removeOrg" org}}></button>
|
||||
{{/github-block}}
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -258,6 +258,25 @@ HEADER {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.project-btn {
|
||||
border: 1px solid #ddd;
|
||||
margin-right: 20px;
|
||||
padding: 0 10px;
|
||||
border-radius: 3px;
|
||||
max-width: 200px;
|
||||
|
||||
.dropdown-toggle {
|
||||
padding: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
max-height: 300px;
|
||||
max-width: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
<div>{{message}}</div>
|
||||
<div style="margin-top: 50px;">
|
||||
<a href="#" onclick="window.location.href = window.location.href; return false;">Reload</a> to try again
|
||||
or <a class="hand" {{action "logout"}}>log out</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,12 +2,6 @@ export default {
|
|||
LOGGED_IN: 'isLoggedIn',
|
||||
ACCESS_WARNING: 'accessWarning',
|
||||
|
||||
GITHUB: {
|
||||
URL: 'https://www.github.com/',
|
||||
API_URL: 'https://api.github.com/',
|
||||
PROXY_URL: '/github/',
|
||||
},
|
||||
|
||||
SESSION: {
|
||||
TOKEN: 'jwt',
|
||||
USER_ID: 'user',
|
||||
|
|
@ -15,8 +9,13 @@ export default {
|
|||
USER_TYPE: 'userType',
|
||||
PROJECT: 'projectId',
|
||||
PROJECT_DEFAULT: 'defaultProject',
|
||||
GITHUB_CACHE: 'githubCache',
|
||||
GITHUB_ORGS: 'orgs',
|
||||
GITHUB_TEAMS: 'teams',
|
||||
},
|
||||
|
||||
TOKEN_TO_SESSION_KEYS: ['accountId', 'defaultProject','jwt','orgs','teams','user','userType'],
|
||||
|
||||
HEADER: {
|
||||
AUTH: 'authorization',
|
||||
AUTH_TYPE: 'Bearer',
|
||||
|
|
@ -35,6 +34,12 @@ export default {
|
|||
TYPE_ADMIN: 'admin',
|
||||
},
|
||||
|
||||
GITHUB: {
|
||||
URL: 'https://www.github.com/',
|
||||
API_URL: 'https://api.github.com/',
|
||||
PROXY_URL: '/github/',
|
||||
},
|
||||
|
||||
PROJECT: {
|
||||
TYPE_RANCHER: 'rancher_id',
|
||||
TYPE_USER: 'github_user',
|
||||
|
|
@ -42,6 +47,11 @@ export default {
|
|||
TYPE_ORG: 'github_org',
|
||||
ROLE_MEMBER: 'member',
|
||||
ROLE_OWNER: 'owner',
|
||||
FROM_GITHUB: {
|
||||
'user': 'github_user',
|
||||
'team': 'github_team',
|
||||
'org': 'github_org',
|
||||
},
|
||||
},
|
||||
|
||||
SETTING: {
|
||||
|
|
|
|||
|
|
@ -3,42 +3,29 @@ import C from 'ui/utils/constants';
|
|||
|
||||
export default Ember.Object.extend({
|
||||
find: function(type, id) {
|
||||
var session = window.l('session:main');
|
||||
var cache = session.get('githubCache')||{};
|
||||
|
||||
if ( type === 'team' )
|
||||
{
|
||||
var entry = (session.get('teams')||[]).filterProperty('id', id)[0];
|
||||
var entry = this.teamById(id);
|
||||
if ( entry )
|
||||
{
|
||||
return Ember.RSVP.resolve(Ember.Object.create({
|
||||
id: id,
|
||||
name: entry.name,
|
||||
type: 'team',
|
||||
description: entry.org + ' team',
|
||||
org: entry.org,
|
||||
avatarUrl: null,
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Ember.RSVP.resolve(Ember.Object.create({
|
||||
id: id,
|
||||
name: '(' + id + ')',
|
||||
type: 'team',
|
||||
description: '(Unknown team)',
|
||||
avatarUrl: null
|
||||
}));
|
||||
return Ember.RSVP.reject('Team ' + id + ' not found');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
type = 'user_or_org';
|
||||
}
|
||||
|
||||
var key = type +':'+ id;
|
||||
if ( cache[id] )
|
||||
var cached = this.getCache(id);
|
||||
if ( cached )
|
||||
{
|
||||
return Ember.RSVP.resolve(cache[id]);
|
||||
return Ember.RSVP.resolve(cached);
|
||||
}
|
||||
|
||||
var url = C.GITHUB.PROXY_URL + 'users/' + id;
|
||||
|
|
@ -51,18 +38,36 @@ export default Ember.Object.extend({
|
|||
avatarUrl: body.avatar_url,
|
||||
});
|
||||
|
||||
cache[key] = out;
|
||||
|
||||
// Sub-keys don't get automatically persisted to the session...
|
||||
session.set('githubCache', cache);
|
||||
|
||||
this.setCache(id,out);
|
||||
return out;
|
||||
});
|
||||
},
|
||||
|
||||
getCache: function(id) {
|
||||
var cache = this.get('session').get(C.SESSION.GITHUB_CACHE)||{};
|
||||
var entry = cache[id];
|
||||
if ( entry )
|
||||
{
|
||||
return Ember.Object.create(entry);
|
||||
}
|
||||
},
|
||||
|
||||
setCache: function(id, value) {
|
||||
var session = this.get('session');
|
||||
var cache = session.get(C.SESSION.GITHUB_CACHE)||{};
|
||||
cache[id] = value;
|
||||
|
||||
// Sub-keys don't get automatically persisted to the session...
|
||||
session.set(C.SESSION.GITHUB_CACHE, cache);
|
||||
},
|
||||
|
||||
teamById: function(id) {
|
||||
return (this.get('session.teams')||[]).filterProperty('id', id)[0];
|
||||
},
|
||||
|
||||
request: function(url) {
|
||||
var headers = {};
|
||||
var session = window.l('session:main');
|
||||
var session = this.get('session');
|
||||
|
||||
var authValue = session.get(C.SESSION.TOKEN);
|
||||
if ( authValue )
|
||||
Loading…
Reference in New Issue