src/app/core/auth/role-form/role-form.component.ts
selector | cd-role-form |
styleUrls | ./role-form.component.scss |
templateUrl | ./role-form.component.html |
Properties |
Methods |
constructor(route: ActivatedRoute, router: Router, roleService: RoleService, scopeService: ScopeService, notificationService: NotificationService, i18n: I18n, actionLabels: ActionLabelsI18n)
|
||||||||||||||||||||||||
Parameters :
|
createAction |
createAction()
|
Returns :
void
|
createForm |
createForm()
|
Returns :
void
|
editAction |
editAction()
|
Returns :
void
|
getRequest |
getRequest()
|
Returns :
RoleFormModel
|
initCreate |
initCreate()
|
Returns :
void
|
initEdit |
initEdit()
|
Returns :
void
|
isHeaderChecked | ||||||||
isHeaderChecked(property: string)
|
||||||||
Checks if the specified header checkbox needs to be rendered as checked.
Parameters :
Returns :
any
Returns true if specified property/permission is selected for all scopes, otherwise false. |
isRowChecked | ||||||||
isRowChecked(scope: string)
|
||||||||
Checks if the specified row checkbox needs to be rendered as checked.
Parameters :
Returns :
any
Returns true if all permissions (read, create, update, delete) are checked for the specified scope, otherwise false. |
listenToChanges |
listenToChanges()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
onClickCellCheckbox | ||||||||||||||||
onClickCellCheckbox(scope: string, property: string, event: Event)
|
||||||||||||||||
Parameters :
Returns :
void
|
onClickHeaderCheckbox | |||||||||
onClickHeaderCheckbox(property: "scope" | "read" | "create" | "update" | "delete", event: Event)
|
|||||||||
Parameters :
Returns :
void
|
submit |
submit()
|
Returns :
void
|
action |
Type : string
|
Public actionLabels |
Type : ActionLabelsI18n
|
cellPermissionCheckboxTpl |
Type : TemplateRef<any>
|
Decorators :
@ViewChild('cellPermissionCheckboxTpl')
|
cellScopeCheckboxTpl |
Type : TemplateRef<any>
|
Decorators :
@ViewChild('cellScopeCheckboxTpl')
|
columns |
Type : CdTableColumn[]
|
headerPermissionCheckboxTpl |
Type : TemplateRef<any>
|
Decorators :
@ViewChild('headerPermissionCheckboxTpl')
|
modalRef |
Type : BsModalRef
|
mode |
Type : RoleFormMode
|
resource |
Type : string
|
response |
Type : RoleFormModel
|
roleForm |
Type : CdFormGroup
|
roleFormMode |
Default value : RoleFormMode
|
scopes |
Type : Array<string>
|
Default value : []
|
scopes_permissions |
Type : Array<any>
|
Default value : []
|
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { I18n } from '@ngx-translate/i18n-polyfill';
import * as _ from 'lodash';
import { BsModalRef } from 'ngx-bootstrap/modal';
import { forkJoin as observableForkJoin } from 'rxjs';
import { RoleService } from '../../../shared/api/role.service';
import { ScopeService } from '../../../shared/api/scope.service';
import { ActionLabelsI18n } from '../../../shared/constants/app.constants';
import { NotificationType } from '../../../shared/enum/notification-type.enum';
import { CdFormGroup } from '../../../shared/forms/cd-form-group';
import { CdValidators } from '../../../shared/forms/cd-validators';
import { CdTableColumn } from '../../../shared/models/cd-table-column';
import { NotificationService } from '../../../shared/services/notification.service';
import { RoleFormMode } from './role-form-mode.enum';
import { RoleFormModel } from './role-form.model';
@Component({
selector: 'cd-role-form',
templateUrl: './role-form.component.html',
styleUrls: ['./role-form.component.scss']
})
export class RoleFormComponent implements OnInit {
@ViewChild('headerPermissionCheckboxTpl')
headerPermissionCheckboxTpl: TemplateRef<any>;
@ViewChild('cellScopeCheckboxTpl')
cellScopeCheckboxTpl: TemplateRef<any>;
@ViewChild('cellPermissionCheckboxTpl')
cellPermissionCheckboxTpl: TemplateRef<any>;
modalRef: BsModalRef;
roleForm: CdFormGroup;
response: RoleFormModel;
columns: CdTableColumn[];
scopes: Array<string> = [];
scopes_permissions: Array<any> = [];
roleFormMode = RoleFormMode;
mode: RoleFormMode;
action: string;
resource: string;
constructor(
private route: ActivatedRoute,
private router: Router,
private roleService: RoleService,
private scopeService: ScopeService,
private notificationService: NotificationService,
private i18n: I18n,
public actionLabels: ActionLabelsI18n
) {
this.resource = this.i18n('role');
this.createForm();
this.listenToChanges();
}
createForm() {
this.roleForm = new CdFormGroup({
name: new FormControl('', {
validators: [Validators.required],
asyncValidators: [CdValidators.unique(this.roleService.exists, this.roleService)]
}),
description: new FormControl(''),
scopes_permissions: new FormControl({})
});
}
ngOnInit() {
this.columns = [
{
prop: 'scope',
name: this.i18n('All'),
flexGrow: 2,
cellTemplate: this.cellScopeCheckboxTpl,
headerTemplate: this.headerPermissionCheckboxTpl
},
{
prop: 'read',
name: this.i18n('Read'),
flexGrow: 1,
cellClass: 'text-center',
cellTemplate: this.cellPermissionCheckboxTpl,
headerTemplate: this.headerPermissionCheckboxTpl
},
{
prop: 'create',
name: this.i18n('Create'),
flexGrow: 1,
cellClass: 'text-center',
cellTemplate: this.cellPermissionCheckboxTpl,
headerTemplate: this.headerPermissionCheckboxTpl
},
{
prop: 'update',
name: this.i18n('Update'),
flexGrow: 1,
cellClass: 'text-center',
cellTemplate: this.cellPermissionCheckboxTpl,
headerTemplate: this.headerPermissionCheckboxTpl
},
{
prop: 'delete',
name: this.i18n('Delete'),
flexGrow: 1,
cellClass: 'text-center',
cellTemplate: this.cellPermissionCheckboxTpl,
headerTemplate: this.headerPermissionCheckboxTpl
}
];
if (this.router.url.startsWith('/user-management/roles/edit')) {
this.mode = this.roleFormMode.editing;
this.action = this.actionLabels.EDIT;
} else {
this.action = this.actionLabels.CREATE;
}
if (this.mode === this.roleFormMode.editing) {
this.initEdit();
} else {
this.initCreate();
}
}
initCreate() {
// Load the scopes and initialize the default scopes/permissions data.
this.scopeService.list().subscribe((scopes: Array<string>) => {
this.scopes = scopes;
this.roleForm.get('scopes_permissions').setValue({});
});
}
initEdit() {
// Disable the 'Name' input field.
this.roleForm.get('name').disable();
// Load the scopes and the role data.
this.route.params.subscribe((params: { name: string }) => {
const observables = [];
observables.push(this.scopeService.list());
observables.push(this.roleService.get(params.name));
observableForkJoin(observables).subscribe((resp: any[]) => {
this.scopes = resp[0];
['name', 'description', 'scopes_permissions'].forEach((key) =>
this.roleForm.get(key).setValue(resp[1][key])
);
});
});
}
listenToChanges() {
// Create/Update the data which is used by the data table to display the
// scopes/permissions every time the form field value has been changed.
this.roleForm.get('scopes_permissions').valueChanges.subscribe((value) => {
const scopes_permissions = [];
_.each(this.scopes, (scope) => {
// Set the defaults values.
const scope_permission = { read: false, create: false, update: false, delete: false };
scope_permission['scope'] = scope;
// Apply settings from the given value if they exist.
if (scope in value) {
_.each(value[scope], (permission) => {
scope_permission[permission] = true;
});
}
scopes_permissions.push(scope_permission);
});
this.scopes_permissions = scopes_permissions;
});
}
/**
* Checks if the specified row checkbox needs to be rendered as checked.
* @param {string} scope The scope to be checked, e.g. 'cephfs', 'grafana',
* 'osd', 'pool' ...
* @return Returns true if all permissions (read, create, update, delete)
* are checked for the specified scope, otherwise false.
*/
isRowChecked(scope: string) {
const scope_permission = _.find(this.scopes_permissions, (o) => {
return o['scope'] === scope;
});
if (_.isUndefined(scope_permission)) {
return false;
}
return (
scope_permission['read'] &&
scope_permission['create'] &&
scope_permission['update'] &&
scope_permission['delete']
);
}
/**
* Checks if the specified header checkbox needs to be rendered as checked.
* @param {string} property The property/permission (read, create,
* update, delete) to be checked. If 'scope' is given, all permissions
* are checked.
* @return Returns true if specified property/permission is selected
* for all scopes, otherwise false.
*/
isHeaderChecked(property: string) {
let permissions = [property];
if ('scope' === property) {
permissions = ['read', 'create', 'update', 'delete'];
}
return permissions.every((permission) => {
return this.scopes_permissions.every((scope_permission) => {
return scope_permission[permission];
});
});
}
onClickCellCheckbox(scope: string, property: string, event: Event = null) {
// Use a copy of the form field data to do not trigger the redrawing of the
// data table with every change.
const scopes_permissions = _.cloneDeep(this.roleForm.getValue('scopes_permissions'));
let permissions = [property];
if ('scope' === property) {
permissions = ['read', 'create', 'update', 'delete'];
}
if (!(scope in scopes_permissions)) {
scopes_permissions[scope] = [];
}
// Add or remove the given permission(s) depending on the click event or if no
// click event is given then add/remove them if they are absent/exist.
if (
(event && event.target['checked']) ||
!_.isEqual(permissions.sort(), _.intersection(scopes_permissions[scope], permissions).sort())
) {
scopes_permissions[scope] = _.union(scopes_permissions[scope], permissions);
} else {
scopes_permissions[scope] = _.difference(scopes_permissions[scope], permissions);
if (_.isEmpty(scopes_permissions[scope])) {
_.unset(scopes_permissions, scope);
}
}
this.roleForm.get('scopes_permissions').setValue(scopes_permissions);
}
onClickHeaderCheckbox(property: 'scope' | 'read' | 'create' | 'update' | 'delete', event: Event) {
// Use a copy of the form field data to do not trigger the redrawing of the
// data table with every change.
const scopes_permissions = _.cloneDeep(this.roleForm.getValue('scopes_permissions'));
let permissions = [property];
if ('scope' === property) {
permissions = ['read', 'create', 'update', 'delete'];
}
_.each(permissions, (permission) => {
_.each(this.scopes, (scope) => {
if (event.target['checked']) {
scopes_permissions[scope] = _.union(scopes_permissions[scope], [permission]);
} else {
scopes_permissions[scope] = _.difference(scopes_permissions[scope], [permission]);
if (_.isEmpty(scopes_permissions[scope])) {
_.unset(scopes_permissions, scope);
}
}
});
});
this.roleForm.get('scopes_permissions').setValue(scopes_permissions);
}
getRequest(): RoleFormModel {
const roleFormModel = new RoleFormModel();
['name', 'description', 'scopes_permissions'].forEach(
(key) => (roleFormModel[key] = this.roleForm.get(key).value)
);
return roleFormModel;
}
createAction() {
const roleFormModel = this.getRequest();
this.roleService.create(roleFormModel).subscribe(
() => {
this.notificationService.show(
NotificationType.success,
this.i18n(`Created role '{{role_name}}'`, { role_name: roleFormModel.name })
);
this.router.navigate(['/user-management/roles']);
},
() => {
this.roleForm.setErrors({ cdSubmitButton: true });
}
);
}
editAction() {
const roleFormModel = this.getRequest();
this.roleService.update(roleFormModel).subscribe(
() => {
this.notificationService.show(
NotificationType.success,
this.i18n(`Updated role '{{role_name}}'`, { role_name: roleFormModel.name })
);
this.router.navigate(['/user-management/roles']);
},
() => {
this.roleForm.setErrors({ cdSubmitButton: true });
}
);
}
submit() {
if (this.mode === this.roleFormMode.editing) {
this.editAction();
} else {
this.createAction();
}
}
}
<div class="col-sm-12 col-lg-6">
<form name="roleForm"
class="form-horizontal"
#formDir="ngForm"
[formGroup]="roleForm"
novalidate>
<div class="panel panel-default">
<div class="panel-heading">
<h3 i18n="form title|Example: Create Pool@@formTitle"
class="panel-title">{{ action | titlecase }} {{ resource | upperFirst }}</h3>
</div>
<div class="panel-body">
<!-- Name -->
<div class="form-group"
[ngClass]="{'has-error': roleForm.showError('name', formDir)}">
<label class="control-label col-sm-3"
for="name">
<ng-container i18n>Name</ng-container>
<span class="required"
*ngIf="mode !== roleFormMode.editing"></span>
</label>
<div class="col-sm-9">
<input class="form-control"
type="text"
i18n-placeholder
placeholder="Name..."
id="name"
name="name"
formControlName="name"
autofocus>
<span class="help-block"
*ngIf="roleForm.showError('name', formDir, 'required')"
i18n>This field is required.</span>
<span class="help-block"
*ngIf="roleForm.showError('name', formDir, 'notUnique')"
i18n>The chosen name is already in use.</span>
</div>
</div>
<!-- Description -->
<div class="form-group"
[ngClass]="{'has-error': roleForm.showError('description', formDir)}">
<label i18n
class="control-label col-sm-3"
for="description">Description</label>
<div class="col-sm-9">
<input class="form-control"
type="text"
i18n-placeholder
placeholder="Description..."
id="description"
name="description"
formControlName="description">
</div>
</div>
<!-- Permissions -->
<div class="form-group">
<label i18n
class="control-label col-sm-3">Permissions</label>
<div class="col-sm-9">
<cd-table [data]="scopes_permissions"
[columns]="columns"
columnMode="flex"
[toolHeader]="false"
[autoReload]="false"
[autoSave]="false"
[footer]="false"
[limit]="0">
</cd-table>
</div>
</div>
</div>
<div class="panel-footer">
<div class="button-group text-right">
<cd-submit-button
[form]="formDir" (submitAction)="submit()"
i18n="form action button|Example: Create Pool@@formActionButton"
type="button">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
<cd-back-button></cd-back-button>
</div>
</div>
</div>
</form>
</div>
<ng-template #cellScopeCheckboxTpl
let-column="column"
let-row="row"
let-value="value">
<div class="checkbox checkbox-primary">
<input id="scope_{{ row.scope }}"
type="checkbox"
[checked]="isRowChecked(row.scope)"
(change)="onClickCellCheckbox(row.scope, column.prop, $event)">
<label class="datatable-permissions-scope-cell-label"
for="scope_{{ row.scope }}">{{ value }}</label>
</div>
</ng-template>
<ng-template #cellPermissionCheckboxTpl
let-column="column"
let-row="row"
let-value="value">
<div class="checkbox checkbox-primary">
<input type="checkbox"
[checked]="value"
(change)="onClickCellCheckbox(row.scope, column.prop, $event)">
<label></label>
</div>
</ng-template>
<ng-template #headerPermissionCheckboxTpl
let-column="column">
<div class="checkbox checkbox-primary">
<input id="header_{{ column.prop }}"
type="checkbox"
[checked]="isHeaderChecked(column.prop)"
(change)="onClickHeaderCheckbox(column.prop, $event)">
<label class="datatable-permissions-header-cell-label"
for="header_{{ column.prop }}">{{ column.name }}</label>
</div>
</ng-template>
./role-form.component.scss
.datatable-permissions-header-cell-label,
.datatable-permissions-scope-cell-label {
font-weight: bold;
}