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: {
|
actions: {
|
||||||
edit: function() {
|
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'),
|
ruleArray: alias('model.role.rules'),
|
||||||
roleArray: null,
|
roleArray: null,
|
||||||
ruleVerbs,
|
ruleVerbs,
|
||||||
|
roleType: null,
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
cancel() {
|
cancel() {
|
||||||
this.get('router').transitionTo('global-admin.roles.index');
|
this.goBack();
|
||||||
},
|
},
|
||||||
addRule() {
|
addRule() {
|
||||||
this.get('ruleArray').pushObject({
|
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 () {
|
init: function () {
|
||||||
this._super();
|
this._super();
|
||||||
this.set('roleArray', (this.get('primaryResource.projectRoleTemplateIds') || []).map(r => {
|
this.set('roleArray', (this.get(`primaryResource.${this.get('roleType')}RoleTemplateIds`) || []).map(r => {
|
||||||
return {
|
return {
|
||||||
value: r
|
value: r
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
otherRoles: function () {
|
||||||
|
return this.get('model.roles').filter(role => this.get('model.role.name') !== role.id);
|
||||||
|
}.property('model'),
|
||||||
|
|
||||||
roleDidChange: function () {
|
roleDidChange: function () {
|
||||||
const role = this.get('model.role');
|
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'),
|
}.observes('roleArray.@each.value'),
|
||||||
|
|
||||||
doesNameExist() {
|
doesNameExist() {
|
||||||
|
|
@ -100,16 +110,17 @@ export default Component.extend(NewOrEdit, {
|
||||||
willSave() {
|
willSave() {
|
||||||
let ok = this._super(...arguments);
|
let ok = this._super(...arguments);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
|
const templateIdsKey = `${this.get('roleType')}RoleTemplateIds`;
|
||||||
const role = this.get('primaryResource');
|
const role = this.get('primaryResource');
|
||||||
const name = (role.get('name') || '').trim().toLowerCase();
|
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('name', name);
|
||||||
role.set('projectRoleTemplateIds', otherRoles);
|
role.set(templateIdsKey, otherRoles);
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
},
|
},
|
||||||
|
|
||||||
doneSaving() {
|
doneSaving() {
|
||||||
this.get('router').transitionTo('global-admin.roles.index');
|
this.goBack();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -1,9 +1,17 @@
|
||||||
<section class="header clearfix">
|
<section class="header clearfix">
|
||||||
<div class="pull-left">
|
<div class="pull-left">
|
||||||
{{#if editing}}
|
{{#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}}
|
{{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}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -38,7 +46,7 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{{#each ruleArray as |rule|}}
|
{{#each ruleArray as |rule|}}
|
||||||
{{role-rule-row rule=rule remove="removeRule"}}
|
{{role-rule-row roleType=roleType rule=rule remove="removeRule"}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
@ -67,7 +75,7 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{{#each roleArray as |role|}}
|
{{#each roleArray as |role|}}
|
||||||
{{other-role-row role=role otherRoles=model.roles remove="removeOtherRole"}}
|
{{other-role-row role=role otherRoles=otherRoles remove="removeOtherRole"}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import { get, set, observer } from '@ember/object'
|
||||||
import C from 'ui/utils/constants';
|
import C from 'ui/utils/constants';
|
||||||
import layout from './template';
|
import layout from './template';
|
||||||
|
|
||||||
const rules = C.PROJECT_ROLE_RULES;
|
|
||||||
const verbs = C.RULE_VERBS;
|
const verbs = C.RULE_VERBS;
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
|
|
@ -11,6 +10,7 @@ export default Component.extend({
|
||||||
rule: null,
|
rule: null,
|
||||||
rules: null,
|
rules: null,
|
||||||
resource: null,
|
resource: null,
|
||||||
|
roleType: null,
|
||||||
|
|
||||||
tagName: 'TR',
|
tagName: 'TR',
|
||||||
classNames: 'main-row',
|
classNames: 'main-row',
|
||||||
|
|
@ -31,6 +31,7 @@ export default Component.extend({
|
||||||
value: currentVerbs.indexOf(verb) > -1,
|
value: currentVerbs.indexOf(verb) > -1,
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
|
const rules = C[`${this.get('roleType').toUpperCase()}_ROLE_RULES`];
|
||||||
this.set('rules', rules.map(rule => {
|
this.set('rules', rules.map(rule => {
|
||||||
return {
|
return {
|
||||||
label: rule,
|
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 Controller from '@ember/controller';
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
import FilterState from 'ui/mixins/filter-state';
|
import FilterState from 'ui/mixins/filter-state';
|
||||||
|
|
||||||
const headers = [
|
const headers = [
|
||||||
|
|
@ -18,4 +19,22 @@ const headers = [
|
||||||
export default Controller.extend(FilterState, {
|
export default Controller.extend(FilterState, {
|
||||||
sortBy: 'name',
|
sortBy: 'name',
|
||||||
headers: headers,
|
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({
|
export default Route.extend({
|
||||||
authzStore: service('authz-store'),
|
authzStore: service('authz-store'),
|
||||||
|
queryParams: {
|
||||||
|
type: 'project',
|
||||||
|
},
|
||||||
model: function (params) {
|
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);
|
const role = roles.findBy('id', params.role_id);
|
||||||
if (!role) {
|
if (!role) {
|
||||||
this.replaceWith('roles.index');
|
this.replaceWith('roles.index', { queryParams: { type: 'project' } });
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
role,
|
role,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ import { inject as service } from '@ember/service';
|
||||||
|
|
||||||
export default Route.extend({
|
export default Route.extend({
|
||||||
authzStore: service('authz-store'),
|
authzStore: service('authz-store'),
|
||||||
model: function () {
|
queryParams: {
|
||||||
return this.get('authzStore').find('projectRoleTemplate', null, { url: 'projectRoleTemplates', forceReload: true, removeMissing: true }).then((roles) => roles);
|
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({
|
export default Route.extend({
|
||||||
authzStore: service('authz-store'),
|
authzStore: service('authz-store'),
|
||||||
model: function () {
|
queryParams: {
|
||||||
|
type: 'project',
|
||||||
|
},
|
||||||
|
model: function (params) {
|
||||||
var role = this.get('authzStore').createRecord({
|
var role = this.get('authzStore').createRecord({
|
||||||
type: 'projectRoleTemplate',
|
type: `${params.type}RoleTemplate`,
|
||||||
name: '',
|
name: '',
|
||||||
rules: [{
|
rules: [{
|
||||||
apiGroups: ['*'],
|
apiGroups: ['*'],
|
||||||
|
|
@ -13,9 +16,9 @@ export default Route.extend({
|
||||||
resources: [],
|
resources: [],
|
||||||
verbs: [],
|
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 {
|
return {
|
||||||
role: role,
|
role: role,
|
||||||
roles: roles,
|
roles: roles,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<section class="header has-tabs clearfix p-0">
|
<section class="header has-tabs clearfix p-0">
|
||||||
<ul class="tab-nav">
|
<ul class="tab-nav">
|
||||||
<li>{{#link-to "accounts"}}{{t 'nav.admin.accounts'}}{{/link-to}}</li>
|
<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 "audit-logs"}}{{t 'nav.admin.audit'}}{{/link-to}}</li>
|
||||||
<li>{{#link-to "catalog"}}{{t 'nav.admin.catalog'}}{{/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>
|
<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,18 +1,18 @@
|
||||||
<section class="header clearfix">
|
{{#roles-header showGroup=false}}
|
||||||
<div class="pull-left">
|
{{#if (eq type "project")}}
|
||||||
<h1>{{t 'rolesPage.index.header'}}</h1>
|
{{#link-to "roles.new" (query-params type="project") classNames="btn btn-sm bg-primary right-divider-btn"}} {{t 'rolesPage.addProjectRole'}} {{/link-to}}
|
||||||
</div>
|
{{else if (eq type "cluster")}}
|
||||||
<div class="right-buttons">
|
{{#link-to "roles.new" (query-params type="cluster") classNames="btn btn-sm bg-primary right-divider-btn"}} {{t 'rolesPage.addClusterRole'}} {{/link-to}}
|
||||||
{{#link-to "roles.new" classNames="btn btn-sm bg-primary right-divider-btn"}} {{t 'rolesPage.addRole'}} {{/link-to}}
|
{{/if}}
|
||||||
</div>
|
{{/roles-header}}
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="instances">
|
<section class="instances">
|
||||||
{{#sortable-table
|
{{#sortable-table
|
||||||
classNames="grid sortable-table"
|
classNames="grid sortable-table"
|
||||||
fullRows=true
|
fullRows=true
|
||||||
sortBy=sortBy
|
sortBy=sortBy
|
||||||
headers=headers
|
headers=headers
|
||||||
|
searchText=searchText
|
||||||
body=filtered
|
body=filtered
|
||||||
as |sortable kind row dt|
|
as |sortable kind row dt|
|
||||||
}}
|
}}
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td data-title="{{t 'rolesPage.index.table.name'}}:" class="clip">
|
<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}}
|
{{row.name}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</td>
|
</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,
|
localizedLabel: false,
|
||||||
// Whether to show the search input box. It maybe useful where the option list is short.
|
// Whether to show the search input box. It maybe useful where the option list is short.
|
||||||
showSearch: true,
|
showSearch: true,
|
||||||
|
searchLabel: 'generic.search',
|
||||||
|
|
||||||
showOptions: false,
|
showOptions: false,
|
||||||
allowCustom: false,
|
allowCustom: false,
|
||||||
|
|
@ -71,6 +72,7 @@ export default Component.extend({
|
||||||
this.set('content', []);
|
this.set('content', []);
|
||||||
}
|
}
|
||||||
if (this.get('allowCustom')) {
|
if (this.get('allowCustom')) {
|
||||||
|
this.set('searchLabel', 'generic.searchOrCustomInput');
|
||||||
const value = this.get('value');
|
const value = this.get('value');
|
||||||
this.insertCustomValue(value, false);
|
this.insertCustomValue(value, false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
{{#if showOptions}}
|
{{#if showOptions}}
|
||||||
<section class="searchable-options {{if showSearch '' 'pt-10'}}">
|
<section class="searchable-options {{if showSearch '' 'pt-10'}}">
|
||||||
{{#if showSearch}}
|
{{#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}}
|
||||||
{{#if prompt}}
|
{{#if prompt}}
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -124,15 +124,18 @@ accountsPage:
|
||||||
|
|
||||||
rolesPage:
|
rolesPage:
|
||||||
index:
|
index:
|
||||||
header: Roles
|
clusterRoles: Cluster Roles
|
||||||
|
projectRoles: Project Roles
|
||||||
localLink: Add Role
|
localLink: Add Role
|
||||||
table:
|
table:
|
||||||
name: Name
|
name: Name
|
||||||
created: Created Time
|
created: Created Time
|
||||||
noData: There are no roles yet
|
noData: There are no roles yet
|
||||||
noMatch: No roles match the current search
|
noMatch: No roles match the current search
|
||||||
addRole: Add Role
|
addProjectRole: Add Project Role
|
||||||
editRole: Edit Role
|
addClusterRole: Add Cluster Role
|
||||||
|
editProjectRole: Edit Project Role
|
||||||
|
editClusterRole: Edit Cluster Role
|
||||||
saveEdit: Edit
|
saveEdit: Edit
|
||||||
saveNew: Create
|
saveNew: Create
|
||||||
new:
|
new:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue