Merge pull request #1714 from westlywright/tech-preview

Tech preview
This commit is contained in:
Vincent Fiduccia 2018-03-06 16:26:29 -07:00 committed by GitHub
commit 7d58bc6504
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 160 additions and 136 deletions

View File

@ -1,10 +1,54 @@
import Resource from 'ember-api-store/models/resource';
import { arrayOfReferences } from 'ember-api-store/utils/denormalize';
import { get, set, computed, observer } from '@ember/object';
import { inject as service } from '@ember/service';
import { allSettled } from 'rsvp';
var GithubConfig = Resource.extend({
type: 'githubConfig',
// TODO WJW - technically this works but we can't get external principals because we currently have no `action=search` by ids for principals
allowedPrincipals: arrayOfReferences('allowedPrincipalIds', 'principal'),
type: 'githubConfig',
globalStore: service(),
_principals: null,
init() {
this._super(...arguments);
if (!get(this, '_principals')) {
set(this, '_principals', []);
}
},
principalIdsChanged: observer('allowedPrincipalIds.[]', function() {
let aPIds = get(this, 'allowedPrincipalIds')||[];
let promises = [];
let store = get(this, 'globalStore');
const principals = [];
if (get(aPIds, 'length')) {
aPIds.forEach(( aID ) => {
promises.push(store.rawRequest({
url: `principals/${encodeURIComponent(aID)}`,
method: 'GET',
}));
});
allSettled(promises).then(( res ) => {
let success = res.filterBy('state', 'fulfilled');
success.forEach( (promise) => {
let principal = get(promise, 'value.body');
principals.push(principal);
});
set(this, '_principals', principals);
})
}
}),
allowedPrincipals: computed('_principals.@each.{id}', function() {
return get(this, '_principals').sortBy('displayName')
}),
});
export default GithubConfig;

View File

@ -12,16 +12,17 @@
background-position: calc(100% - 10px) center;
}
.input-search {
@extend .input-arrow;
&:hover{
@extend .input-arrow;
}
&:focus{
&.show-dropdown-arrow {
.input-search {
@extend .input-arrow;
&:hover{
@extend .input-arrow;
}
&:focus{
@extend .input-arrow;
}
}
}
.searchable-option-active {
background: $link-hover-color;
color: white;

View File

@ -117,7 +117,7 @@ export default Controller.extend({
'clientId' : (githubConfig.get('clientId')||'').trim(),
'clientSecret' : (githubConfig.get('clientSecret')||'').trim(),
'enabled' : false, // It should already be, but just in case..
'accessMode' : 'unrestricted',
'accessMode' : 'restricted',
'tls': true,
'allowedPrincipalIds' : [],
});

View File

@ -10,6 +10,8 @@ export default Route.extend({
return hash({
githubConfig: gs.find('authconfig', 'github'),
principals: gs.findAll('principal')
}).catch( e => {
return e;
})
},

View File

@ -1,3 +1,4 @@
import Errors from 'ui/utils/errors';
import Component from '@ember/component'
import { all as PromiseAll } from 'rsvp';
import { inject as service } from '@ember/service';
@ -151,6 +152,12 @@ export default Component.extend(NewOrEdit,{
actions: {
gotError: function(err) {
set(this, 'errors', [Errors.stringify(err)]);
},
addAuthorized: function(principal) {
set(this, 'principal', principal);
},
cancel() {
this.sendAction('cancel');
},
@ -163,10 +170,10 @@ export default Component.extend(NewOrEdit,{
let principal = get(this, 'principal');
if (principal) {
if (get(principal, 'type') === 'user') {
set(pr, 'userPrincipalId', get(principal, 'value'))
if (get(principal, 'principalType') === 'user') {
set(pr, 'userPrincipalId', get(principal, 'id'))
} else if (get(principal, 'type') === 'group') {
set(pr, 'groupPrincipalId', get(principal, 'value'))
set(pr, 'groupPrincipalId', get(principal, 'id'))
}
}

View File

@ -1,7 +1,7 @@
<div class="row">
<div class="col span-6">
<label class="acc-label">{{t 'generic.member'}}</label>
{{principal-search errors=(mut errors) principal=principal}}
{{input-identity allowTeams=true action="addAuthorized" onError="gotError"}}
</div>
<div class="col span-12">
</div>
@ -15,14 +15,14 @@
}}
<div class="radio">
<label>
{{radio-button selection=mode value=stdUser}} {{t 'formScopedRoles.mode.user.label' type=cTyped}}
<p class="help-block">{{t 'formScopedRoles.mode.user.detail' type=cTyped}}</p>
{{radio-button selection=mode value=admin}} {{t 'formScopedRoles.mode.admin.label' type=cTyped}}
<p class="help-block">{{t 'formScopedRoles.mode.admin.detail' type=cTyped}}</p>
</label>
</div>
<div class="radio">
<label>
{{radio-button selection=mode value=admin}} {{t 'formScopedRoles.mode.admin.label' type=cTyped}}
<p class="help-block">{{t 'formScopedRoles.mode.admin.detail' type=cTyped}}</p>
{{radio-button selection=mode value=stdUser}} {{t 'formScopedRoles.mode.user.label' type=cTyped}}
<p class="help-block">{{t 'formScopedRoles.mode.user.detail' type=cTyped}}</p>
</label>
</div>
{{#each userRoles as |role| }}

View File

@ -41,7 +41,7 @@ export default Component.extend({
// if (!get(this, 'globalStore').hasRecordFor(principal.type, principal.id)) {
// get(this, 'globalStore')._add('principal', principal);
// }
this.send('addObject', get(principal, 'id'));
this.send('addObject', principal);
}

View File

@ -1,15 +1,8 @@
<form {{action "add" on="submit"}}>
<div class="input-group">
{{!-- {{input type="text" value=addInput placeholder=(t (if (eq access.provider 'githubconfig') 'inputIdentity.placeholder.generic' 'inputIdentity.placeholder.github')) class="form-control"}} --}}
{{principal-search principal=addInput useLabel=true}}
{{principal-search principal=addInput useLabel=true add="add"}}
<div class="input-group-btn">
{{#if checking}}
<button class="btn bg-primary btn-disabled"><i class="icon icon-spinner icon-spin"></i></button>
{{else}}
<button class="btn bg-primary" {{action "add"}} disabled={{addDisabled}}><i class="icon icon-plus"></i></button>
{{/if}}
{{#if showDropdown}}
<button type="button" class="btn bg-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu" style="min-width: 250px; max-height: 300px; overflow-y: auto;">

View File

@ -11,6 +11,7 @@ import { isAlternate, isMore, isRange } from 'ui/utils/platform';
const DEBOUNCE_MS = 250;
export default SearchableSelect.extend({
classNames: 'principal-search',
globalStore: service(),
errors: null,
content: alias('filteredPrincipals'),
@ -18,11 +19,12 @@ export default SearchableSelect.extend({
_principals: null,
_ourPrincipals: null,
useLabel: null,
showDropdownArrow: false,
clientSideFiltering: false,
filteredPrincipals: computed('_principals.@each.{id,state}', function() {
return get(this, '_principals').map(( principal ) =>{
return ( get(this, '_principals') || [] ).map(( principal ) =>{
// console.log({label: get(principal, 'displayName') || get(principal, 'loginName') || get(principal, 'name'), value: get(principal, 'id'), provider: get(principal, 'provider'),});
return {
label: get(principal, 'displayName') || get(principal, 'loginName') || get(principal, 'name'),
@ -30,16 +32,8 @@ export default SearchableSelect.extend({
provider: get(principal, 'provider'),
type: get(principal, 'principalType')
};
}).sortBy('label');
}),
init() {
set(this, '_principals', get(this, 'globalStore').all('principal'));
get(this, 'globalStore').findAll('principal').then((principals) => {
set(this, '_ourPrincipals', principals);
});
this._super(...arguments);
},
}),
externalChanged: on('init', observer('external', function(){
let principal = get(this, 'external');
@ -64,6 +58,7 @@ export default SearchableSelect.extend({
metas: computed(function() {
return Object.keys(C.KEY).map(k => C.KEY[k]);
}),
actions: {
search(term, e) {
const kc = e.keyCode;
@ -72,7 +67,6 @@ export default SearchableSelect.extend({
&& !isAlternate(k)
&& !isRange(k)
&& !isMore(k);
}
if (isAlpha(kc)) {
get(this, 'search').perform(term);
@ -129,6 +123,7 @@ export default SearchableSelect.extend({
})
set(this, 'principal', item);
this.sendAction('add');
this.send('hide');
},

View File

@ -1,3 +1,4 @@
import Errors from 'ui/utils/errors';
import Component from '@ember/component';
import layout from './template';
import { computed, get, set, setProperties, observer } from '@ember/object';
@ -47,8 +48,8 @@ export default Component.extend({
let principal = (get(this, 'principal'));
if (principal) {
set(this, 'member.memberId', get(principal, 'value'));
set(this, 'member.memberType', get(principal, 'type'));
set(this, 'member.memberId', get(principal, 'id'));
set(this, 'member.memberType', get(principal, 'principalType'));
}
}),
@ -62,6 +63,7 @@ export default Component.extend({
}
if (member && member.principalId) {
set(this, 'noUpdate', true);
get(this, 'globalStore').rawRequest({
url: `principals/${encodeURIComponent(get(this, 'member.principalId'))}`,
method: 'GET',
@ -72,7 +74,6 @@ export default Component.extend({
if ( xhr.body && typeof xhr.body === 'object') {
set(this, 'principal', set(this, 'external', xhr.body));
set(this, 'noUpdate', true);
this.principalChanged();
}
return xhr;
@ -89,6 +90,12 @@ export default Component.extend({
},
actions: {
gotError: function(err) {
set(this, 'errors', [Errors.stringify(err)]);
},
addAuthorized: function(principal) {
set(this, 'principal', principal);
},
onSelect(selected) {
if(selected.value === 'custom') {
next(() => {

View File

@ -2,15 +2,22 @@
{{#if owner}}
{{owner.displayName}}
{{else}}
{{!-- {{searchable-select content=userList value=member.memberId}} --}}
{{principal-search errors=(mut errors) principal=principal external=external}}
{{#if noUpdate}}
{{principal.displayName}}
{{else}}
{{input-identity allowTeams=true action="addAuthorized" onError="gotError"}}
{{/if}}
{{/if}}
</td>
<td class="pr-10">
{{#if owner}}
{{t 'generic.owner'}}
{{else}}
{{searchable-select change="onSelect" content=choices value=roleTemplateId readOnly=noUpdate}}
{{#if noUpdate}}
{{roleTemplateId}}
{{else}}
{{searchable-select change="onSelect" content=choices value=roleTemplateId readOnly=noUpdate}}
{{/if}}
{{/if}}
</td>
<td>&nbsp;</td>

View File

@ -34,7 +34,7 @@ export default Component.extend({
intl: service(),
classNames: ['searchable-select'],
classNameBindings: ['class'],
classNameBindings: ['class', 'showDropdownArrow'],
// input
class: null,
@ -60,6 +60,7 @@ export default Component.extend({
// the current highlighted option.
$activeTarget: null,
maxHeight: MAX_HEIGHT,
showDropdownArrow: true,
actions: {
search(/*term*/) {

View File

@ -3,44 +3,43 @@ import Component from '@ember/component';
import Errors from 'ui/utils/errors';
import layout from './template';
import { get, set, observer } from '@ember/object';
import { on } from '@ember/object/evented';
export default Component.extend({
layout,
tagName: 'section',
classNames: ['well'],
settings: service(),
access: service(),
github: service(),
tagName: 'section',
classNames: ['well'],
settings: service(),
access: service(),
github: service(),
model: null,
model: null,
individuals: 'siteAccess.users',
collection: 'siteAccess.groups',
principals: null,
collection: 'siteAccess.groups',
principals: null,
saved: true,
errors: null,
saved: true,
errors: null,
showList: function() {
return get(this, 'copy.accessMode') !== 'unrestricted';
}.property('copy.accessMode'),
return get(this, 'model.accessMode') !== 'unrestricted';
}.property('model.accessMode'),
actions: {
addAuthorized: function(id) {
addAuthorized: function(principal) {
this.send('clearError');
set(this, 'saved', false);
get(this, 'copy.allowedPrincipalIds').pushObject(id);
get(this, 'model.allowedPrincipalIds').addObject(principal.id);
},
removeAuthorized: function(id) {
set(this, 'saved', false);
get(this, 'copy.allowedPrincipalIds').removeObject(id);
get(this, 'model.allowedPrincipalIds').removeObject(ident.id);
},
save: function(btnCb) {
this.send('clearError');
if ( get(this, 'showList') && !get(this, 'copy.allowedPrincipalIds.length') )
if ( get(this, 'showList') && !get(this, 'model.allowedPrincipalIds.length') )
{
this.send('gotError', 'You must add at least one authorized entry');
btnCb();
@ -49,10 +48,8 @@ export default Component.extend({
set(this, 'saved', false);
let copy = get(this, 'copy');
copy.save().then(() => {
get(this, 'model').replaceWith(copy);
set(this, 'copy.allowedPrincipalIds', get(this, 'copy.allowedPrincipalIds').slice());
let model = get(this, 'model');
model.save().then(() => {
set(this, 'saved', true);
}).catch((err) => {
this.send('gotError', err);
@ -72,32 +69,30 @@ export default Component.extend({
init() {
this._super(...arguments);
set(this, 'copy', get(this, 'model').clone());
set(this, 'copy.allowedPrincipalIds', (get(this, 'copy.allowedPrincipalIds')||[]).slice());
this.accessModeChanged();
},
accessModeChanged: observer('copy.accessMode', function() {
accessModeChanged: observer('model.accessMode', function() {
set(this, 'saved',false);
let identities = get(this, 'copy.allowedPrincipalIds'); // ['princ_id1://yada']
if ( !identities )
let allowedPrincipals = get(this, 'model.allowedPrincipalIds'); // ['princ_id1://yada']
if ( !allowedPrincipals )
{
identities = [];
set(this, 'copy.allowedPrincipalIds', identities);
allowedPrincipals = [];
set(this, 'model.allowedPrincipalIds', allowedPrincipals);
}
if ( get(this, 'copy.accessMode') !== 'unrestricted' )
{
let me = get(this, 'access.me.principalIds');
let found = identities.filter((ident) => {
return me.includes(ident);
}).length > 0;
if ( !found )
{
// TODO?
identities = identities.concat(me).uniq();
}
}
// if ( get(this, 'model.accessMode') !== 'unrestricted' )
// {
// let me = get(this, 'access.me.principalIds')||[];
// let found = allowedPrincipals.filter((ident) => {
// return me.includes(ident);
// }).length > 0;
// if ( found ) {
// } else {
// // TODO?
// allowedPrincipals = allowedPrincipals.concat(me).uniq();
// }
// }
}),
});

View File

@ -8,34 +8,35 @@
<div class="row">
<div class="col span-7">
<div class="radio">
<label>{{radio-button selection=copy.accessMode value="unrestricted"}} {{t 'siteAccess.unrestricted' individuals=(t individuals) collection=(t collection)}}</label>
<label>{{radio-button selection=model.accessMode value="unrestricted"}} {{t 'siteAccess.unrestricted' individuals=(t individuals) collection=(t collection)}}</label>
</div>
<div class="radio">
<label>{{radio-button selection=copy.accessMode value="restricted"}} {{t 'siteAccess.restricted' individuals=(t individuals) collection=(t collection)}}</label>
<label>{{radio-button selection=model.accessMode value="restricted"}} {{t 'siteAccess.restricted' individuals=(t individuals) collection=(t collection)}}</label>
</div>
<div class="radio">
<label>{{radio-button selection=copy.accessMode value="required"}} {{t 'siteAccess.required' individuals=(t individuals) collection=(t collection)}}</label>
<label>{{radio-button selection=model.accessMode value="required"}} {{t 'siteAccess.required' individuals=(t individuals) collection=(t collection)}}</label>
</div>
</div>
<div class="col span-5">
{{#if showList}}
{{input-identity allowTeams=false action="addAuthorized" onError="gotError"}}
{{input-identity allowTeams=true action="addAuthorized" onError="gotError"}}
<hr/>
<h5>{{t 'siteAccess.listHeader' individuals=(t individuals) collection=(t collection)}}</h5>
<ul class="list-unstyled gh-block-list mt-10">
{{#each copy.allowedPrincipals as |item|}}
{{#each model.allowedPrincipals as |item|}}
<li>
{{#identity-block principal=item}}
<button class="btn bg-primary btn-sm pull-right gh-action" {{action "removeAuthorized" item.id}} disabled={{array-includes access.me.principalIds item.id}}><i class="icon icon-minus"/></button>
{{/identity-block}}
</li>
{{else}}
<li>
<span class="text-muted">{{t 'siteAccess.noIdentity'}}</span>
</li>
{{/each}}
</ul>
{{#if (eq copy.allowedIdentities.length 0)}}
<span class="text-muted">{{t 'siteAccess.noIdentity'}}</span>
{{/if}}
{{/if}}
</div>
</div>

View File

@ -85,7 +85,7 @@ export default Service.extend({
},
finishTest(config, code, cb) {
let ghConfig = config.clone();
let ghConfig = config;
let out = {
code: code,
enabled: true,
@ -93,8 +93,16 @@ export default Service.extend({
};
return this.saveConfig(config, out).then(() => {
get(this, 'access').detect(); // Update the list of providers...
cb();
return get(this, 'globalStore').find('principal', null, {filter: {me: true, provider: 'github'}}).then(( resp ) => {
let me = resp.find( (p) => {
return get(p, 'me') && get(p, 'provider') === 'github';// TODO filters do not work but craig knows
});
out.githubConfig.allowedPrincipalIds.push(me.id);
return ghConfig.save().then(() => {
get(this, 'access').detect(); // Update the list of providers...
cb();
});
});
}).catch((err) => {
cb(err);
});

View File

@ -1195,21 +1195,6 @@ broccoli-babel-transpiler@^5.6.1:
rsvp "^3.5.0"
workerpool "^2.2.1"
broccoli-babel-transpiler@^5.6.2:
version "5.7.4"
resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.4.tgz#2b0611ce9e5d98b8d8d2b49ae1219af2f52767e3"
dependencies:
babel-core "^5.0.0"
broccoli-funnel "^1.0.0"
broccoli-merge-trees "^1.0.0"
broccoli-persistent-filter "^1.4.2"
clone "^0.2.0"
hash-for-dep "^1.0.2"
heimdalljs-logger "^0.1.7"
json-stable-stringify "^1.0.0"
rsvp "^3.5.0"
workerpool "^2.3.0"
broccoli-babel-transpiler@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.0.0.tgz#a52c5404bf36236849da503b011fd41fe64a00a2"
@ -2717,17 +2702,7 @@ ember-cli-app-version@^3.0.0:
ember-cli-babel "^6.8.0"
git-repo-version "0.4.1"
ember-cli-babel@^5.1.6, ember-cli-babel@^5.1.7, ember-cli-babel@^5.2.1, ember-cli-babel@^5.2.4:
version "5.2.4"
resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13"
dependencies:
broccoli-babel-transpiler "^5.6.2"
broccoli-funnel "^1.0.0"
clone "^2.0.0"
ember-cli-version-checker "^1.0.2"
resolve "^1.1.2"
ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.3.0, ember-cli-babel@^6.7.1, ember-cli-babel@^6.7.2, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2:
ember-cli-babel@^5.1.6, ember-cli-babel@^5.1.7, ember-cli-babel@^5.2.1, ember-cli-babel@^5.2.4, ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.3.0, ember-cli-babel@^6.7.1, ember-cli-babel@^6.7.2, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2:
version "6.8.2"
resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.8.2.tgz#eac2785964f4743f4c815cd53c6288f00cc087d7"
dependencies:
@ -6466,12 +6441,6 @@ resolve@1.3.2:
dependencies:
path-parse "^1.0.5"
resolve@^1.1.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36"
dependencies:
path-parse "^1.0.5"
resolve@^1.1.3, resolve@^1.1.4, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86"
@ -7519,12 +7488,6 @@ workerpool@^2.2.1:
dependencies:
object-assign "4.1.1"
workerpool@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-2.3.0.tgz#86c5cbe946b55e7dc9d12b1936c8801a6e2d744d"
dependencies:
object-assign "4.1.1"
wrap-ansi@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"