Support cluster role

This commit is contained in:
loganhz 2017-11-24 10:39:32 +08:00
parent dbc43c574e
commit 86965f55a0
20 changed files with 163 additions and 37 deletions

View File

@ -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;

View File

@ -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' } });
},
},

View File

@ -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();
},
});

View File

@ -1,9 +1,17 @@
<section class="header clearfix">
<div class="pull-left">
{{#if editing}}
<h1>{{t 'rolesPage.editRole'}}</h1>
{{#if (eq roleType "project")}}
<h1>{{t 'rolesPage.editProjectRole'}}</h1>
{{else if (eq roleType "cluster")}}
<h1>{{t 'rolesPage.editClusterRole'}}</h1>
{{/if}}
{{else}}
<h1>{{t 'rolesPage.addRole'}}</h1>
{{#if (eq roleType "project")}}
<h1>{{t 'rolesPage.addProjectRole'}}</h1>
{{else if (eq roleType "cluster")}}
<h1>{{t 'rolesPage.addClusterRole'}}</h1>
{{/if}}
{{/if}}
</div>
</section>
@ -38,7 +46,7 @@
</thead>
<tbody>
{{#each ruleArray as |rule|}}
{{role-rule-row rule=rule remove="removeRule"}}
{{role-rule-row roleType=roleType rule=rule remove="removeRule"}}
{{/each}}
</tbody>
</table>
@ -67,7 +75,7 @@
</thead>
<tbody>
{{#each roleArray as |role|}}
{{other-role-row role=role otherRoles=model.roles remove="removeOtherRole"}}
{{other-role-row role=role otherRoles=otherRoles remove="removeOtherRole"}}
{{/each}}
</tbody>
</table>

View File

@ -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,

View File

@ -0,0 +1,6 @@
import Component from '@ember/component';
import layout from './template';
export default Component.extend({
layout,
});

View File

@ -0,0 +1,10 @@
<section class="header has-tabs clearfix p-0">
<ul class="tab-nav">
<li>{{#link-to "roles.index" (query-params type="project")}}{{t 'rolesPage.index.projectRoles'}}{{/link-to}}</li>
<li>{{#link-to "roles.index" (query-params type="cluster")}}{{t 'rolesPage.index.clusterRoles'}}{{/link-to}}</li>
</ul>
<div class="right-buttons">
{{yield}}
</div>
</section>

View File

@ -0,0 +1,7 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default Controller.extend({
queryParams: ['type'],
type: 'project',
});

View File

@ -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'),
});

View File

@ -0,0 +1,7 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default Controller.extend({
queryParams: ['type'],
type: 'project',
});

View File

@ -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,

View File

@ -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);
},
});

View File

@ -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,

View File

@ -2,7 +2,7 @@
<section class="header has-tabs clearfix p-0">
<ul class="tab-nav">
<li>{{#link-to "accounts"}}{{t 'nav.admin.accounts'}}{{/link-to}}</li>
<li>{{#link-to "roles"}}{{t 'nav.admin.roles'}}{{/link-to}}</li>
<li>{{#link-to "roles.index"}}{{t 'nav.admin.roles'}}{{/link-to}}</li>
<li>{{#link-to "audit-logs"}}{{t 'nav.admin.audit'}}{{/link-to}}</li>
<li>{{#link-to "catalog"}}{{t 'nav.admin.catalog'}}{{/link-to}}</li>
<li>{{#link-to "settings.auth"}}{{t 'nav.admin.settings.auth'}}{{/link-to}}</li>

View File

@ -1 +1 @@
{{new-edit-role model=model editing=true}}
{{new-edit-role model=model editing=true roleType=type}}

View File

@ -1,18 +1,18 @@
<section class="header clearfix">
<div class="pull-left">
<h1>{{t 'rolesPage.index.header'}}</h1>
</div>
<div class="right-buttons">
{{#link-to "roles.new" classNames="btn btn-sm bg-primary right-divider-btn"}} {{t 'rolesPage.addRole'}} {{/link-to}}
</div>
</section>
{{#roles-header showGroup=false}}
{{#if (eq type "project")}}
{{#link-to "roles.new" (query-params type="project") classNames="btn btn-sm bg-primary right-divider-btn"}} {{t 'rolesPage.addProjectRole'}} {{/link-to}}
{{else if (eq type "cluster")}}
{{#link-to "roles.new" (query-params type="cluster") classNames="btn btn-sm bg-primary right-divider-btn"}} {{t 'rolesPage.addClusterRole'}} {{/link-to}}
{{/if}}
{{/roles-header}}
<section class="instances">
{{#sortable-table
classNames="grid sortable-table"
fullRows=true
sortBy=sortBy
headers=headers
searchText=searchText
body=filtered
as |sortable kind row dt|
}}
@ -22,7 +22,7 @@
&nbsp;
</td>
<td data-title="{{t 'rolesPage.index.table.name'}}:" class="clip">
{{#link-to "roles.edit" row.id}}
{{#link-to "roles.edit" row.id (query-params type=type)}}
{{row.name}}
{{/link-to}}
</td>

View File

@ -1 +1 @@
{{new-edit-role model=model editing=false}}
{{new-edit-role model=model editing=false roleType=type}}

View File

@ -49,6 +49,7 @@ export default Component.extend({
localizedLabel: false,
// Whether to show the search input box. It maybe useful where the option list is short.
showSearch: true,
searchLabel: 'generic.search',
showOptions: false,
allowCustom: false,
@ -71,6 +72,7 @@ export default Component.extend({
this.set('content', []);
}
if (this.get('allowCustom')) {
this.set('searchLabel', 'generic.searchOrCustomInput');
const value = this.get('value');
this.insertCustomValue(value, false);
}

View File

@ -6,7 +6,7 @@
{{#if showOptions}}
<section class="searchable-options {{if showSearch '' 'pt-10'}}">
{{#if showSearch}}
{{input class=(concat 'form-control ' class) placeholder=(t 'generic.searchOrCustomInput') type="text" value=filter}}
{{input class=(concat 'form-control ' class) placeholder=(t searchLabel) type="text" value=filter}}
{{/if}}
{{#if prompt}}
<div

View File

@ -124,15 +124,18 @@ accountsPage:
rolesPage:
index:
header: Roles
clusterRoles: Cluster Roles
projectRoles: Project Roles
localLink: Add Role
table:
name: Name
created: Created Time
noData: There are no roles yet
noMatch: No roles match the current search
addRole: Add Role
editRole: Edit Role
addProjectRole: Add Project Role
addClusterRole: Add Cluster Role
editProjectRole: Edit Project Role
editClusterRole: Edit Cluster Role
saveEdit: Edit
saveNew: Create
new: