Merge pull request #1588 from westlywright/tech-preview

Tech preview
This commit is contained in:
Vincent Fiduccia 2018-01-22 22:21:31 -07:00 committed by GitHub
commit b3b0375c48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 314 additions and 75 deletions

View File

@ -1,10 +1,10 @@
import { computed } from '@ember/object';
import { get, computed, set } from '@ember/object';
import { inject as service } from '@ember/service';
import Controller from '@ember/controller';
export default Controller.extend({
access: service(),
sortBy: 'name',
sortBy: null,
headers: computed('isLocal', function() {
let out = [
{
@ -26,6 +26,11 @@ export default Controller.extend({
return out;
}),
init() {
this._super(...arguments);
set(this, 'sortBy', get(this, 'isLocal') ? 'username' : 'name');
},
isLocal: computed('access.provider', function() {
return true; // TODO 2.0
// return this.get('access.provider') === 'localauthconfig';

View File

@ -24,14 +24,4 @@ export default Route.extend({
}
});
},
setupController(controller, model) {
this._super(...arguments);
controller.set('errors', null);
let bindings = (get(model,'cluster.clusterRoleTemplateBindings')||[]).slice();
bindings = bindings.filter(x =>get(x, 'name') !== 'creator');
set(controller, 'memberArray', bindings);
}
});

View File

@ -21,10 +21,9 @@
}}
{{form-members
creator=model.me
editing=false
memberArray=memberArray
editing=true
memberConfig=memberConfig
project=primaryResource
primaryResource=primaryResource
roles=model.roles
users=model.users
type="cluster"

View File

@ -112,9 +112,8 @@
{{form-members
creator=model.me
editing=false
memberArray=memberArray
memberConfig=memberConfig
project=primaryResource
primaryResource=primaryResource
roles=model.roles
users=model.users
type="cluster"

View File

@ -1,54 +1,115 @@
import Component from '@ember/component';
import layout from './template';
import { computed, observer, get, set } from '@ember/object';
import { on } from '@ember/object/evented';
import { computed, get, set, setProperties } from '@ember/object';
import { inject as service } from '@ember/service';
import { all as PromiseAll } from 'rsvp';
export default Component.extend({
layout,
globalStore: service(),
access: service(),
globalStore: service(),
access: service(),
editing: false,
memberArray: null,
memberConfig: null,
model: null,
project: null,
roles: null,
type: null,
users: null,
creator: null,
showCreator: true,
toAdd: null,
toUpdate: null,
toRemove: null,
editing: false,
memberArray: null,
memberConfig: null,
model: null,
primaryResource: null,
roles: null,
type: null,
users: null,
creator: null,
showCreator: true,
toAddCustom: null,
_bindings: null,
init() {
this._super(...arguments);
set(this, 'toAdd', []);
set(this, 'toUpdate', []);
set(this, 'toRemove', []);
this.buildUpdateList(get(this,'primaryResource'))
this.sendAction('initAlert', this.primaryResourceSaved.bind(this));
},
didReceiveAttrs() {
let ma = get(this, 'memberArray').filter(( m ) => {
return get(m, 'roleTemplateId').indexOf('-owner') < 0 && !get(this, 'toAdd').includes(m);
});
if (ma && get(ma, 'length') > 0) {
set(this, 'toUpdate', ma);
buildUpdateList(resource) {
let bindingType = `${get(resource, 'type')}RoleTemplateBindings`;
let bindings = get(resource, bindingType).filter(b => b.name !== 'creator');
let existing = [];
let grouped = {};
set(this, "_bindings", bindings.slice());
if (bindings && get(this, 'editing')) {
bindings.forEach((b) => {
if (grouped[get(b, 'subjectName')]) {
grouped[get(b, 'subjectName')].push(b);
} else {
grouped[get(b, 'subjectName')] = [b];
}
});
if (grouped) {
Object.keys(grouped).forEach((g) => {
if (grouped[g].length >1) {
let idsOut = [];
grouped[g].forEach((m) => {
idsOut.push(get(m, 'roleTemplateId'))
});
let config = get(this, 'memberConfig');
set(config, 'subjectKind', 'User'); //should be upper but make sure
set(config, 'subjectName', g);
let record = get(this,'globalStore').createRecord(config);
let out = {
role: record,
toUpdate: false,
toAdd: false,
toDelete: false,
customRolesExisting: idsOut
}
existing.push(out);
} else {
existing.push({
role: grouped[g][0],
toUpdate: true,
toAdd: false,
toDelete: false,
id: Math.random()
})
}
});
}
}
set(this, 'memberArray', existing);
},
primaryResourceSaved: function() {
// returns a promise of all the adds/removes/updates to the parent
const pr = get(this, 'project');
const pr = get(this, 'primaryResource');
const resourceId = get(pr, 'id');
const add = (get(this, 'toAdd')||[]);
const update = get(this, 'toUpdate')||[];
const remove = get(this, 'toRemove')||[];
const memberArray = get(this, 'memberArray').slice();
const customToAdd = memberArray.filterBy('customRolesToAdd');
const customToRemove = memberArray.filterBy('customRolesToRemove');
const add = get(this, 'memberArray').filter(r => get(r, 'toAdd') && !get(r, 'customRolesToAdd')).map(a => a.role);
const update = get(this, 'memberArray').filterBy('toUpdate', true).map(u => u.role);
const remove = get(this, 'memberArray').filterBy('toDelete', true).map(r => r.role);
customToRemove.forEach((rm) => {
// custom obj from custom
get(rm, 'customRolesToRemove').forEach((roleTempId) => {
let match = get(this, '_bindings').find((binding) => {
if (get(binding, 'roleTemplateId') === roleTempId) {
return binding;
}
});
remove.push(match);
});
});
customToAdd.forEach((m) => {
get(m, 'customRolesToAdd').forEach((a) => {
let role = get(m, 'role').clone();
set(role, 'roleTemplateId', a);
add.addObject(role);
})
});
add.forEach((x) => {
x.set(`${get(this, 'type')}Id`, resourceId);
@ -58,6 +119,7 @@ export default Component.extend({
return PromiseAll(add.map(x => x.save())).then(() => {
return PromiseAll(update.map(x => x.save())).then(() => {
return PromiseAll(remove.map(x => x.delete())).then(() => {
set(this, 'memberArray', []);
return pr;
});
});
@ -65,6 +127,11 @@ export default Component.extend({
},
actions: {
setCustomToAdd(member, customIds, customIdsRemove) {
set(member, 'customRolesToAdd', customIds);
set(member, 'customRolesToRemove', customIdsRemove);
},
cancel() {
this.goBack();
},
@ -74,18 +141,37 @@ export default Component.extend({
set(config, 'subjectKind', kind.capitalize()); //should be upper but make sure
// not setting the name correctly
let record = get(this,'globalStore').createRecord(config);
get(this,'memberArray').pushObject(record);
get(this, 'toAdd').pushObject(record);
let out = {
role: record,
toAdd: true,
toUpate: false,
toDelete: false,
id: Math.random()
};
get(this,'memberArray').pushObject(out);
},
removeMember(obj) {
get(this,'memberArray').removeObject(obj);
get(this, 'toRemove').pushObject(obj);
let exists = get(this, 'memberArray').findBy('id', get(obj, 'id'));
if (get(obj, 'toAdd') && exists) {
// we just added and should remove it because the record has not been persisted yet
get(this,'memberArray').removeObject(obj);
} else if (exists) {
setProperties(exists, {
toAdd: false,
toUpdate: false,
toDelete: true,
});
}
},
},
filteredUsers: computed('users.@each.{id,state}', function() {
return get(this, 'users').sortBy('displayName');
let users = get(this, 'users');
if (get(this, 'editing')) {
users = users.filter(u => !u.hasOwnProperty('me'));
}
return users.sortBy('displayName');
}),
});

View File

@ -10,9 +10,25 @@
</tr>
</thead>
<tbody>
{{project-member-row member=member roles=roles users=users owner=creator type=type}}
{{project-member-row
roles=roles
users=users
owner=creator
type=type
}}
{{#each memberArray as |member|}}
{{project-member-row member=member roles=roles users=filteredUsers remove="removeMember" }}
{{#unless member.toDelete}}
{{project-member-row
member=member
editing=editing
resource=primaryResource
roles=roles
users=filteredUsers
pageType=primaryResource.type
remove="removeMember"
alertNewCustoms=(action "setCustomToAdd")
}}
{{/unless}}
{{/each}}
</tbody>
</table>

View File

@ -9,7 +9,7 @@
{{#accordion-list-item
title=(t 'formScopedRoles.title' type=cTyped)
detail=(t 'formScopedRoles.description')
detail=(t 'formScopedRoles.description' type=cTyped)
expandOnInit=true
showExpand=false
}}

View File

@ -0,0 +1,44 @@
import Component from '@ember/component';
import ModalBase from 'shared/mixins/modal-base';
import layout from './template';
import { get, set } from '@ember/object';
import { alias } from 'ember-computed';
export default Component.extend(ModalBase, {
layout,
classNames: ['small-modal'],
type: alias('modalOpts.type'),
init() {
this._super(...arguments);
let custom = get(this, 'modalOpts.roles').filterBy('hidden', false).filter((role) => {
return role.get('id') !== `${get(this, 'type')}-owner` && role.get('id') !== `${get(this, 'type')}-member`;
}).map((role) => {
let binding = null;
if ( get(this, 'modalOpts.current') ) {
binding = get(this, 'modalOpts.current').findBy('roleTemplateId', get(role, 'id'));
}
return {
role,
active: !!binding,
existing: binding,
}
});
set(this, 'custom', custom)
},
actions: {
save() {
get(this, 'modalOpts.done')(get(this, 'custom'));
this.get('modalService').toggleModal();
},
completed() {
this.get('modalService').toggleModal();
},
goBack() {
this.get('modalService').toggleModal();
},
},
});

View File

@ -0,0 +1,24 @@
<section class="header">
<h1>Custom Roles</h1>
</section>
<section>
{{#accordion-list-item
title=(t 'formScopedRoles.title' type=type)
detail=(t 'formScopedRoles.description' type=type)
expandOnInit=true
showExpand=false
}}
<div class="pl-20">
{{#each custom as |row|}}
<div class="box p-10 mt-5 mb-5">
<label>
{{input type="checkbox" checked=row.active}} {{row.role.displayName}}
<p class="help-block">{{row.role.detail}}</p>
</label>
</div>
{{/each}}
</div>
{{/accordion-list-item}}
</section>
{{save-cancel save="save" cancel="goBack" createLabel="generic.save"}}

View File

@ -33,9 +33,8 @@
{{form-members
creator=creator
editing=editing
memberArray=memberArray
memberConfig=memberConfig
project=primaryResource
primaryResource=primaryResource
roles=model.roles
users=model.users
type="project"

View File

@ -1,7 +1,23 @@
import Component from '@ember/component';
import layout from './template';
import { computed, observer, get, set } from '@ember/object';
import { computed, get, observer, set, setProperties } from '@ember/object';
import { on } from '@ember/object/evented';
import { inject as service } from '@ember/service';
const BASIC_ROLES = [
{
label: 'Standard User',
value: 'member',
},
{
label: 'Admin',
value: 'owner',
},
{
label: 'Custom',
value: 'custom',
},
];
export default Component.extend({
layout,
@ -12,23 +28,77 @@ export default Component.extend({
roles: null,
owner: null,
type: null,
pageType: null,
modalService: service('modal'),
hasCustom: false,
customRoles: null,
actions: {
showEdit(member) {
if (get(member, 'role.roleTemplateId') === 'custom'){
this.openModal();
} else {
set(member, 'role.roleTemplateId', 'custom');
}
},
remove: function () {
this.sendAction('remove', get(this,'member'));
}
},
init: function () {
this._super(...arguments);
set(this, 'choices', get(this,'roles').filterBy('hidden', false).map(role => {
return {
label: role.name,
value: role.id,
};
}));
doneAdding(customs) {
setProperties(this, {
hasCustom: true,
customRoles: customs
});
let customIds = [];
let customIdsRemove = [];
customs.forEach((c) => {
if (get(c, 'active') && !get(c, 'existing')) {
customIds.push(get(c, 'role.id'));
}
if (get(c, 'existing') && !get(c, 'active')) {
customIdsRemove.push(get(c, 'role.id'));
}
});
this.alertNewCustoms(get(this, 'member'), customIds, customIdsRemove);
},
openModal() {
let current = null;
if (get(this, 'member.customRolesExisting')) {
current = get(this, `resource.${get(this, 'pageType')}RoleTemplateBindings`);
}
// append roletemplate ids from the modal to the custom field. split that field in the add promise of form-members?
get(this,'modalService').toggleModal('modal-add-custom-roles', {
model: get(this, 'member'),
roles: get(this, 'roles'),
done: this.doneAdding.bind(this),
current: current,
type: get(this, 'pageType')
});
},
openCustomModal: on('init', observer('member.role.roleTemplateId', function() {
if (get(this, 'member.role.roleTemplateId') === 'custom') {
this.openModal();
}
})),
choices: computed('roles.[]', 'pageType', function() {
let pt = get(this, 'pageType');
if (pt) {
return BASIC_ROLES.map((r) => {
return {
label: r.label,
value: r.value.indexOf('custom') >= 0 ? 'custom' : `${pt}-${r.value}`
};
});
}
return [];
}),
userList: computed('users.[]', function() {
return (get(this, 'users')||[]).map(( user ) =>{
return {
@ -38,11 +108,11 @@ export default Component.extend({
});
}),
kind: computed('member.subjectKind', function () {
kind: computed('member.role.subjectKind', function () {
if (get(this, 'owner')) {
return `projectsPage.new.form.members.${get(this,'owner.type').toLowerCase()}`; // TODO translations
} else {
return `projectsPage.new.form.members.${get(this,'member.subjectKind').toLowerCase()}`
return `projectsPage.new.form.members.${get(this,'member.role.subjectKind').toLowerCase()}`
}
}),

View File

@ -4,20 +4,26 @@
<td class="pr-20">
{{#if owner}}
{{owner.displayName}}
{{else if editing}}
{{member.role.user.displayName}}
{{else}}
{{searchable-select content=userList value=member.subjectName disabled=true}}
{{searchable-select content=userList value=member.role.subjectName}}
{{/if}}
</td>
<td class="pr-20">
{{#if owner}}
{{if (eq type 'project') 'Project Owner' 'Cluster Owner'}}
{{else if (or hasCustom member.customRolesExisting)}}
Multple Roles <span class="edit btn-sm hand" {{action "showEdit" member}}><i class="icon icon-edit"></i></span>
{{else}}
{{searchable-select content=choices value=member.roleTemplateId}}
{{searchable-select content=choices value=member.role.roleTemplateId}}
{{/if}}
</td>
<td>&nbsp;</td>
<div class="input-group-btn">
<button class="btn bg-primary btn-sm" {{action "remove"}} disabled={{if owner 'true' null}}>
<i class="icon icon-minus" />
</button>
{{#unless owner}}
<button class="btn bg-primary btn-sm" {{action "remove"}}>
<i class="icon icon-minus" />
</button>
{{/unless}}
</div>

View File

@ -0,0 +1 @@
export { default } from 'shared/components/modal-add-custom-roles/component';

View File

@ -2240,7 +2240,7 @@ formGlobalRoles:
formScopedRoles:
title: '{type} Permissions'
description: TBD.
description: 'Controls what access users have to the {type}.'
mode:
admin:
label: Owner