mirror of https://github.com/rancher/ui.git
Support cluster role
This commit is contained in:
parent
dbc43c574e
commit
86965f55a0
|
|
@ -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;
|
||||
|
|
@ -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' } });
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
},
|
||||
});
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
import Component from '@ember/component';
|
||||
import layout from './template';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
});
|
||||
|
|
@ -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>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import Controller from '@ember/controller';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default Controller.extend({
|
||||
queryParams: ['type'],
|
||||
type: 'project',
|
||||
});
|
||||
|
|
@ -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'),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
import Controller from '@ember/controller';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default Controller.extend({
|
||||
queryParams: ['type'],
|
||||
type: 'project',
|
||||
});
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{{new-edit-role model=model editing=true}}
|
||||
{{new-edit-role model=model editing=true roleType=type}}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
<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
|
||||
|
|
@ -13,6 +12,7 @@
|
|||
fullRows=true
|
||||
sortBy=sortBy
|
||||
headers=headers
|
||||
searchText=searchText
|
||||
body=filtered
|
||||
as |sortable kind row dt|
|
||||
}}
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
</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>
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{{new-edit-role model=model editing=false}}
|
||||
{{new-edit-role model=model editing=false roleType=type}}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Reference in New Issue