diff --git a/app/models/clusterroletemplate.js b/app/models/clusterroletemplate.js new file mode 100644 index 000000000..855f336d7 --- /dev/null +++ b/app/models/clusterroletemplate.js @@ -0,0 +1,43 @@ +import { inject as service } from '@ember/service'; +import { getOwner } from '@ember/application'; +import { next } from '@ember/runloop'; + +import Resource from 'ember-api-store/models/resource'; +import PolledResource from 'ui/mixins/cattle-polled-resource'; + +var ClusterRoleTemplate = Resource.extend(PolledResource, { + type: 'clusterRoleTemplate', + router: service(), + + actions: { + edit: function () { + this.get('router').transitionTo('global-admin.roles.edit', this.get('id'), { queryParams: { type: 'cluster' } }); + }, + }, + + availableActions: function () { + return [ + { label: 'action.edit', icon: 'icon icon-edit', action: 'edit', enabled: true }, + { divider: true }, + { label: 'action.remove', icon: 'icon icon-trash', action: 'promptDelete', enabled: true, altAction: 'delete', bulkable: true }, + { divider: true }, + { label: 'action.viewInApi', icon: 'icon icon-external-link', action: 'goToApi', enabled: true }, + ]; + }.property(), + + delete: function (/*arguments*/) { + var promise = this._super.apply(this, arguments); + return promise.then(() => { + this.set('state', 'removed'); + }).catch((err) => { + this.get('growl').fromError('Error deleting', err); + }); + }, +}); + +ClusterRoleTemplate.reopenClass({ + pollTransitioningDelay: 1000, + pollTransitioningInterval: 5000, +}); + +export default ClusterRoleTemplate; diff --git a/app/models/projectroletemplate.js b/app/models/projectroletemplate.js index a22c487cf..26e45ee73 100644 --- a/app/models/projectroletemplate.js +++ b/app/models/projectroletemplate.js @@ -11,7 +11,7 @@ var ProjectRoleTemplate = Resource.extend(PolledResource, { actions: { edit: function() { - this.get('router').transitionTo('global-admin.roles.edit', this.get('id')); + this.get('router').transitionTo('global-admin.roles.edit', this.get('id'), { queryParams: { type: 'project' } }); }, }, diff --git a/lib/global-admin/addon/components/new-edit-role/component.js b/lib/global-admin/addon/components/new-edit-role/component.js index 967b2c45e..d0ebd7297 100644 --- a/lib/global-admin/addon/components/new-edit-role/component.js +++ b/lib/global-admin/addon/components/new-edit-role/component.js @@ -15,10 +15,11 @@ export default Component.extend(NewOrEdit, { ruleArray: alias('model.role.rules'), roleArray: null, ruleVerbs, + roleType: null, actions: { cancel() { - this.get('router').transitionTo('global-admin.roles.index'); + this.goBack(); }, addRule() { this.get('ruleArray').pushObject({ @@ -41,18 +42,27 @@ export default Component.extend(NewOrEdit, { }, }, + goBack: function() { + const route = this.get('roleType') === 'project' ? '/admin/roles' : '/admin/roles?type=cluster' + this.get('router').transitionTo(route); + }, + init: function () { this._super(); - this.set('roleArray', (this.get('primaryResource.projectRoleTemplateIds') || []).map(r => { + this.set('roleArray', (this.get(`primaryResource.${this.get('roleType')}RoleTemplateIds`) || []).map(r => { return { value: r }; })); }, + otherRoles: function () { + return this.get('model.roles').filter(role => this.get('model.role.name') !== role.id); + }.property('model'), + roleDidChange: function () { const role = this.get('model.role'); - role.set('projectRoleTemplateIds', (this.get('roleArray') || []).filter(r => r.value).map(r => r.value)); + role.set(`${this.get('roleType')}RoleTemplateIds`, (this.get('roleArray') || []).filter(r => r.value).map(r => r.value)); }.observes('roleArray.@each.value'), doesNameExist() { @@ -100,16 +110,17 @@ export default Component.extend(NewOrEdit, { willSave() { let ok = this._super(...arguments); if (ok) { + const templateIdsKey = `${this.get('roleType')}RoleTemplateIds`; const role = this.get('primaryResource'); const name = (role.get('name') || '').trim().toLowerCase(); - const otherRoles = role.get('projectRoleTemplateIds').filter(r => r).uniq(); + const otherRoles = role.get(templateIdsKey).filter(r => r).uniq(); role.set('name', name); - role.set('projectRoleTemplateIds', otherRoles); + role.set(templateIdsKey, otherRoles); } return ok; }, doneSaving() { - this.get('router').transitionTo('global-admin.roles.index'); + this.goBack(); }, }); \ No newline at end of file diff --git a/lib/global-admin/addon/components/new-edit-role/template.hbs b/lib/global-admin/addon/components/new-edit-role/template.hbs index cef1e69c7..b2a8cbf0b 100644 --- a/lib/global-admin/addon/components/new-edit-role/template.hbs +++ b/lib/global-admin/addon/components/new-edit-role/template.hbs @@ -1,9 +1,17 @@
{{#if editing}} -

{{t 'rolesPage.editRole'}}

+ {{#if (eq roleType "project")}} +

{{t 'rolesPage.editProjectRole'}}

+ {{else if (eq roleType "cluster")}} +

{{t 'rolesPage.editClusterRole'}}

+ {{/if}} {{else}} -

{{t 'rolesPage.addRole'}}

+ {{#if (eq roleType "project")}} +

{{t 'rolesPage.addProjectRole'}}

+ {{else if (eq roleType "cluster")}} +

{{t 'rolesPage.addClusterRole'}}

+ {{/if}} {{/if}}
@@ -38,7 +46,7 @@ {{#each ruleArray as |rule|}} - {{role-rule-row rule=rule remove="removeRule"}} + {{role-rule-row roleType=roleType rule=rule remove="removeRule"}} {{/each}} @@ -67,7 +75,7 @@ {{#each roleArray as |role|}} - {{other-role-row role=role otherRoles=model.roles remove="removeOtherRole"}} + {{other-role-row role=role otherRoles=otherRoles remove="removeOtherRole"}} {{/each}} diff --git a/lib/global-admin/addon/components/role-rule-row/component.js b/lib/global-admin/addon/components/role-rule-row/component.js index d1584367a..a48fb4379 100644 --- a/lib/global-admin/addon/components/role-rule-row/component.js +++ b/lib/global-admin/addon/components/role-rule-row/component.js @@ -3,7 +3,6 @@ import { get, set, observer } from '@ember/object' import C from 'ui/utils/constants'; import layout from './template'; -const rules = C.PROJECT_ROLE_RULES; const verbs = C.RULE_VERBS; export default Component.extend({ @@ -11,6 +10,7 @@ export default Component.extend({ rule: null, rules: null, resource: null, + roleType: null, tagName: 'TR', classNames: 'main-row', @@ -31,6 +31,7 @@ export default Component.extend({ value: currentVerbs.indexOf(verb) > -1, }; })); + const rules = C[`${this.get('roleType').toUpperCase()}_ROLE_RULES`]; this.set('rules', rules.map(rule => { return { label: rule, diff --git a/lib/global-admin/addon/components/roles-header/component.js b/lib/global-admin/addon/components/roles-header/component.js new file mode 100644 index 000000000..50b86e6ba --- /dev/null +++ b/lib/global-admin/addon/components/roles-header/component.js @@ -0,0 +1,6 @@ +import Component from '@ember/component'; +import layout from './template'; + +export default Component.extend({ + layout, +}); diff --git a/lib/global-admin/addon/components/roles-header/template.hbs b/lib/global-admin/addon/components/roles-header/template.hbs new file mode 100644 index 000000000..4e3ed50e2 --- /dev/null +++ b/lib/global-admin/addon/components/roles-header/template.hbs @@ -0,0 +1,10 @@ +
+ + +
+ {{yield}} +
+
diff --git a/lib/global-admin/addon/controllers/roles/edit.js b/lib/global-admin/addon/controllers/roles/edit.js new file mode 100644 index 000000000..f6f9be640 --- /dev/null +++ b/lib/global-admin/addon/controllers/roles/edit.js @@ -0,0 +1,7 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default Controller.extend({ + queryParams: ['type'], + type: 'project', +}); diff --git a/lib/global-admin/addon/controllers/roles/index.js b/lib/global-admin/addon/controllers/roles/index.js index ee76d28df..69e157b05 100644 --- a/lib/global-admin/addon/controllers/roles/index.js +++ b/lib/global-admin/addon/controllers/roles/index.js @@ -1,4 +1,5 @@ import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; import FilterState from 'ui/mixins/filter-state'; const headers = [ @@ -18,4 +19,22 @@ const headers = [ export default Controller.extend(FilterState, { sortBy: 'name', headers: headers, + queryParams: ['type'], + authzStore: service('authz-store'), + type: 'project', + searchText: '', + + onRoleTypeChanged: function () { + const roleType = this.get('type'); + return this.get('authzStore').find(`${roleType}RoleTemplate`, null, { + url: `${roleType}RoleTemplates`, + forceReload: true, + removeMissing: true, + sortBy: 'name', + }) + .then((roles) => { + this.set('model', roles); + this.set('searchText', ''); + }); + }.observes('type'), }); diff --git a/lib/global-admin/addon/controllers/roles/new.js b/lib/global-admin/addon/controllers/roles/new.js new file mode 100644 index 000000000..01932dce9 --- /dev/null +++ b/lib/global-admin/addon/controllers/roles/new.js @@ -0,0 +1,7 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default Controller.extend({ + queryParams: ['type'], + type: 'project', +}); \ No newline at end of file diff --git a/lib/global-admin/addon/routes/roles/edit.js b/lib/global-admin/addon/routes/roles/edit.js index e3ada89f8..8275fd484 100644 --- a/lib/global-admin/addon/routes/roles/edit.js +++ b/lib/global-admin/addon/routes/roles/edit.js @@ -3,11 +3,14 @@ import { inject as service } from '@ember/service'; export default Route.extend({ authzStore: service('authz-store'), + queryParams: { + type: 'project', + }, model: function (params) { - return this.get('authzStore').find('projectRoleTemplate', null, { url: 'projectRoleTemplates', forceReload: true, removeMissing: true }).then((roles) => { + return this.get('authzStore').find(`${params.type}RoleTemplate`, null, { url: `${params.type}RoleTemplates`, forceReload: true, removeMissing: true }).then((roles) => { const role = roles.findBy('id', params.role_id); if (!role) { - this.replaceWith('roles.index'); + this.replaceWith('roles.index', { queryParams: { type: 'project' } }); } return { role, diff --git a/lib/global-admin/addon/routes/roles/index.js b/lib/global-admin/addon/routes/roles/index.js index 8d9d113cf..e4fc9ba3b 100644 --- a/lib/global-admin/addon/routes/roles/index.js +++ b/lib/global-admin/addon/routes/roles/index.js @@ -3,7 +3,10 @@ import { inject as service } from '@ember/service'; export default Route.extend({ authzStore: service('authz-store'), - model: function () { - return this.get('authzStore').find('projectRoleTemplate', null, { url: 'projectRoleTemplates', forceReload: true, removeMissing: true }).then((roles) => roles); + queryParams: { + type: 'project', + }, + model: function (params) { + return this.get('authzStore').find(`${params.type}RoleTemplate`, null, { url: `${params.type}RoleTemplates`, forceReload: true, removeMissing: true }).then((roles) => roles); }, }); diff --git a/lib/global-admin/addon/routes/roles/new.js b/lib/global-admin/addon/routes/roles/new.js index 4fd1bdd29..c8046ee9f 100644 --- a/lib/global-admin/addon/routes/roles/new.js +++ b/lib/global-admin/addon/routes/roles/new.js @@ -3,9 +3,12 @@ import { inject as service } from '@ember/service'; export default Route.extend({ authzStore: service('authz-store'), - model: function () { + queryParams: { + type: 'project', + }, + model: function (params) { var role = this.get('authzStore').createRecord({ - type: 'projectRoleTemplate', + type: `${params.type}RoleTemplate`, name: '', rules: [{ apiGroups: ['*'], @@ -13,9 +16,9 @@ export default Route.extend({ resources: [], verbs: [], }], - projectRoleTemplateIds: [''], }); - return this.get('authzStore').find('projectRoleTemplate', null, { url: 'projectRoleTemplates', forceReload: true, removeMissing: true }).then((roles) => { + role.set(`${params.type}RoleTemplateIds`, ['']); + return this.get('authzStore').find(`${params.type}RoleTemplate`, null, { url: `${params.type}RoleTemplates`, forceReload: true, removeMissing: true }).then((roles) => { return { role: role, roles: roles, diff --git a/lib/global-admin/addon/templates/application.hbs b/lib/global-admin/addon/templates/application.hbs index c54f96d8c..4474bb56e 100644 --- a/lib/global-admin/addon/templates/application.hbs +++ b/lib/global-admin/addon/templates/application.hbs @@ -2,7 +2,7 @@