diff --git a/lib/global-admin/addon/accounts/index/controller.js b/lib/global-admin/addon/accounts/index/controller.js index 12d1ab30e..f4dbd5c3c 100644 --- a/lib/global-admin/addon/accounts/index/controller.js +++ b/lib/global-admin/addon/accounts/index/controller.js @@ -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'; diff --git a/lib/global-admin/addon/clusters/detail/edit/route.js b/lib/global-admin/addon/clusters/detail/edit/route.js index 6d059a7d1..ed2016eab 100644 --- a/lib/global-admin/addon/clusters/detail/edit/route.js +++ b/lib/global-admin/addon/clusters/detail/edit/route.js @@ -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); - } }); diff --git a/lib/global-admin/addon/clusters/detail/edit/template.hbs b/lib/global-admin/addon/clusters/detail/edit/template.hbs index 098d1b61e..e26d2659f 100644 --- a/lib/global-admin/addon/clusters/detail/edit/template.hbs +++ b/lib/global-admin/addon/clusters/detail/edit/template.hbs @@ -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" diff --git a/lib/global-admin/addon/clusters/new/rke/template.hbs b/lib/global-admin/addon/clusters/new/rke/template.hbs index 92e9d52ec..75e65b2dd 100644 --- a/lib/global-admin/addon/clusters/new/rke/template.hbs +++ b/lib/global-admin/addon/clusters/new/rke/template.hbs @@ -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" diff --git a/lib/shared/addon/components/form-members/component.js b/lib/shared/addon/components/form-members/component.js index 73cf028fe..35bbe5ddf 100644 --- a/lib/shared/addon/components/form-members/component.js +++ b/lib/shared/addon/components/form-members/component.js @@ -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'); }), }); diff --git a/lib/shared/addon/components/form-members/template.hbs b/lib/shared/addon/components/form-members/template.hbs index 1e3234f2b..4002e6946 100644 --- a/lib/shared/addon/components/form-members/template.hbs +++ b/lib/shared/addon/components/form-members/template.hbs @@ -10,9 +10,25 @@
- {{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}} diff --git a/lib/shared/addon/components/form-scoped-roles/template.hbs b/lib/shared/addon/components/form-scoped-roles/template.hbs index 5fd755376..bd233ba87 100644 --- a/lib/shared/addon/components/form-scoped-roles/template.hbs +++ b/lib/shared/addon/components/form-scoped-roles/template.hbs @@ -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 }} diff --git a/lib/shared/addon/components/modal-add-custom-roles/component.js b/lib/shared/addon/components/modal-add-custom-roles/component.js new file mode 100644 index 000000000..66ee2b453 --- /dev/null +++ b/lib/shared/addon/components/modal-add-custom-roles/component.js @@ -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(); + }, + }, +}); diff --git a/lib/shared/addon/components/modal-add-custom-roles/template.hbs b/lib/shared/addon/components/modal-add-custom-roles/template.hbs new file mode 100644 index 000000000..f52ceefac --- /dev/null +++ b/lib/shared/addon/components/modal-add-custom-roles/template.hbs @@ -0,0 +1,24 @@ +