[ADF-2556] Created component for add group or user to permission (#3242)

* [ADF-2556] first step to create add people or group to permissions

* [ADF-2556] creating a dialog with user results

* [ADF-2556]
integrated service for add and remove permission from node

* [ADF-2556] fixed behaviour and style for add user group

* [ADF-2556] added some refactoring for dialog service

* [ADF-2556] refactoring the dependencies of the components

* [ADF-2556] added some fix and a new key for dialog

* [ADF-2556] start adding test for node permission service

* [ADF-2556] added test for add permission panel component

* [ADf-2556] adding tests for new add permission component

* [ADF-2556] fixed tests and added documentation

* [ADF-2556] fixed documentation for add-node components

* [ADF-2556] added peer review changes
This commit is contained in:
Vito
2018-05-03 15:14:15 +01:00
committed by Eugenio Romano
parent 61a4173ad3
commit 513915b3d9
37 changed files with 1576 additions and 25 deletions

View File

@@ -0,0 +1,25 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { MinimalNodeEntity } from 'alfresco-js-api';
import { Subject } from 'rxjs/Subject';
export interface AddPermissionDialogData {
title?: string;
nodeId: string;
confirm: Subject<MinimalNodeEntity[]>;
}

View File

@@ -0,0 +1,16 @@
<h2 mat-dialog-title id="add-permission-dialog-title">
{{(data?.title ? data?.title : 'PERMISSION_MANAGER.ADD-PERMISSION.BASE-DIALOG-TITLE') | translate}}
</h2>
<mat-dialog-content>
<adf-add-permission-panel
(select)="onSelect($event)">
</adf-add-permission-panel>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button mat-dialog-close id="add-permission-dialog-close-button">{{'PERMISSION_MANAGER.ADD-PERMISSION.CLOSE-ACTION' | translate}}</button>
<button mat-button id="add-permission-dialog-confirm-button" [mat-dialog-close]="true"
class="choose-action"
[disabled]="currentSelection?.length === 0"
(click)="onAddClicked()">{{'PERMISSION_MANAGER.ADD-PERMISSION.ADD-ACTION' | translate}}</button>
</mat-dialog-actions>

View File

@@ -0,0 +1,55 @@
@mixin adf-add-permission-dialog-theme($theme) {
$primary: map-get($theme, primary);
$foreground: map-get($theme, foreground);
$background: map-get($theme, background);
.adf-add-permission-dialog {
.mat-dialog-title {
margin-left: 24px;
margin-right: 24px;
font-size: 20px;
font-weight: 600;
font-style: normal;
font-stretch: normal;
line-height: 1.6;
letter-spacing: -0.5px;
color: mat-color($foreground, text, 0.87);
}
.mat-dialog-container {
padding-left: 0;
padding-right: 0;
}
.mat-dialog-content {
margin: 0;
overflow: hidden;
}
.mat-dialog-actions {
padding: 8px;
background-color: mat-color($background, background);
display: flex;
justify-content: flex-end;
color: mat-color($foreground, secondary-text);
button {
text-transform: uppercase;
font-weight: normal;
}
.choose-action {
&[disabled] {
opacity: 0.6;
}
&:enabled {
color: mat-color($primary);
}
}
}
}
}

View File

@@ -0,0 +1,111 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { ContentTestingModule } from '../../../testing/content.testing.module';
import { By } from '@angular/platform-browser';
import { setupTestBed } from '@alfresco/adf-core';
import { AddPermissionDialogComponent } from './add-permission-dialog.component';
import { MinimalNodeEntity } from 'alfresco-js-api';
import { Subject } from 'rxjs/Subject';
import { AddPermissionDialogData } from './add-permission-dialog-data.interface';
import { fakeAuthorityResults } from '../../../mock/add-permission.component.mock';
import { AddPermissionPanelComponent } from './add-permission-panel.component';
describe('AddPermissionDialog', () => {
let fixture: ComponentFixture<AddPermissionDialogComponent>;
let element: HTMLElement;
let data: AddPermissionDialogData = {
title: 'dead or alive you are coming with me',
nodeId: 'fake-node-id',
confirm: new Subject<MinimalNodeEntity[]> ()
};
const dialogRef = {
close: jasmine.createSpy('close')
};
setupTestBed({
imports: [ContentTestingModule],
providers: [
{ provide: MatDialogRef, useValue: dialogRef },
{ provide: MAT_DIALOG_DATA, useValue: data }
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
beforeEach(() => {
fixture = TestBed.createComponent(AddPermissionDialogComponent);
element = fixture.nativeElement;
fixture.detectChanges();
});
afterEach(() => {
fixture.destroy();
});
it('should show the INJECTED title', () => {
const titleElement = fixture.debugElement.query(By.css('#add-permission-dialog-title'));
expect(titleElement).not.toBeNull();
expect(titleElement.nativeElement.innerText).toBe('dead or alive you are coming with me');
});
it('should close the dialog when close button is clicked', () => {
const closeButton: HTMLButtonElement = <HTMLButtonElement> element.querySelector('#add-permission-dialog-close-button');
expect(closeButton).not.toBeNull();
closeButton.click();
expect(dialogRef.close).toHaveBeenCalled();
});
it('should disable the confirm button when no selection is applied', () => {
const confirmButton: HTMLButtonElement = <HTMLButtonElement> element.querySelector('#add-permission-dialog-confirm-button');
expect(confirmButton.disabled).toBeTruthy();
});
it('should enable the button when a selection is done', async(() => {
const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(By.directive(AddPermissionPanelComponent)).componentInstance;
addPermissionPanelComponent.select.emit(fakeAuthorityResults);
let confirmButton: HTMLButtonElement = <HTMLButtonElement> element.querySelector('#add-permission-dialog-confirm-button');
expect(confirmButton.disabled).toBeTruthy();
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
confirmButton = <HTMLButtonElement> element.querySelector('#add-permission-dialog-confirm-button');
expect(confirmButton.disabled).toBeFalsy();
});
}));
it('should stream the confirmed selection on the confirm subject', async(() => {
const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(By.directive(AddPermissionPanelComponent)).componentInstance;
addPermissionPanelComponent.select.emit(fakeAuthorityResults);
data.confirm.subscribe((selection) => {
expect(selection[0]).not.toBeNull();
expect(selection[0].entry.id).not.toBeNull();
expect(fakeAuthorityResults[0].entry.id).toBe(selection[0].entry.id);
});
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
const confirmButton = <HTMLButtonElement> element.querySelector('#add-permission-dialog-confirm-button');
confirmButton.click();
});
}));
});

View File

@@ -0,0 +1,48 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, ViewEncapsulation, Inject, ViewChild } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material';
import { MinimalNodeEntity } from 'alfresco-js-api';
import { AddPermissionDialogData } from './add-permission-dialog-data.interface';
import { AddPermissionComponent } from '../add-permission/add-permission.component';
@Component({
selector: 'adf-add-permission-dialog',
templateUrl: './add-permission-dialog.component.html',
styleUrls: ['./add-permission-dialog.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class AddPermissionDialogComponent {
@ViewChild('addPermission')
addPermissionComponent: AddPermissionComponent;
private currentSelection: MinimalNodeEntity[] = [];
constructor(@Inject(MAT_DIALOG_DATA) public data: AddPermissionDialogData) {
}
onSelect(items: MinimalNodeEntity[]) {
this.currentSelection = items;
}
onAddClicked() {
this.data.confirm.next(this.currentSelection);
this.data.confirm.complete();
}
}

View File

@@ -0,0 +1,54 @@
<mat-form-field floatPlaceholder="never" class="adf-permission-search-input">
<input matInput
id="searchInput"
[formControl]="searchInput"
type="text"
placeholder="{{'PERMISSION_MANAGER.ADD-PERMISSION.SEARCH' | translate}}"
[value]="searchedWord">
<mat-icon *ngIf="searchedWord?.length > 0"
class="adf-permission-search-icon"
data-automation-id="adf-permission-clear-input"
id="adf-permission-clear-input"
matSuffix (click)="clearSearch()">clear
</mat-icon>
<mat-icon *ngIf="searchedWord?.length === 0"
class="adf-permission-search-icon"
data-automation-id="adf-permission-search-icon"
matSuffix>search
</mat-icon>
</mat-form-field>
<div *ngIf="searchedWord?.length === 0" id="adf-add-permission-type-search">
<span class="adf-permission-start-message">{{'PERMISSION_MANAGER.ADD-PERMISSION.TYPE-MESSAGE' | translate}}</span>
</div>
<adf-search #search [searchTerm]="searchedWord"
id="adf-add-permission-authority-results"
class="adf-permission-result-list"
*ngIf="searchedWord.length !== 0">
<ng-template let-data>
<mat-selection-list [class.adf-permission-result-list-elements]="data?.list?.entries.length !== 0">
<mat-list-option *ngFor="let item of data?.list?.entries; let idx = index"
(click)="elementClicked(item)"
class="adf-list-option-item"
id="result_option_{{idx}}">
<mat-icon mat-list-icon id="add-group-icon"
*ngIf="item?.entry?.nodeType === 'cm:authorityContainer' else show_person_icon">
group_add
</mat-icon>
<ng-template #show_person_icon>
<mat-icon id="add-person-icon" mat-list-icon>person_add</mat-icon>
</ng-template>
<p>
{{item.entry?.properties['cm:authorityName']?
item.entry?.properties['cm:authorityName'] :
item.entry?.properties['cm:firstName']}}</p>
</mat-list-option>
</mat-selection-list>
<div *ngIf="data?.list?.entries.length === 0" class="adf-permission-no-result" id="adf-add-permission-no-results">
<span>{{'PERMISSION_MANAGER.ADD-PERMISSION.NO-RESULT' | translate}}</span>
</div>
</ng-template>
</adf-search>

View File

@@ -0,0 +1,68 @@
@mixin adf-add-permission-panel-theme($theme) {
$background: map-get($theme, background);
$foreground: map-get($theme, foreground);
$primary: map-get($theme, primary);
$accent: map-get($theme, accent);
$mat-menu-border-radius: 2px !default;
.adf {
&-permission-result-list {
display: flex;
height: 300px;
overflow: auto;
border: 2px solid mat-color($foreground, base, 0.07);
&-elements {
width: 100%;
}
}
&-permission-start-message {
display: flex;
align-items: center;
justify-content: space-around;
height: 300px;
overflow: auto;
border: 2px solid mat-color($foreground, base, 0.07);
}
&-permission-no-result{
display: flex;
align-items: center;
justify-content: space-around;
width: 100%;
}
&-permission-search {
&-input {
width: 100%;
&-icon {
color: mat-color($foreground, disabled-button);
cursor: pointer;
&:hover {
color: mat-color($foreground, base);
}
}
}
}
&-list-option-item .mat-list-text {
display: flex;
flex-direction: row !important;
align-items: center;
}
&-permission-action {
&[disabled] {
opacity: 0.6;
}
&:enabled {
color: mat-color($primary);
}
}
}
}

View File

@@ -0,0 +1,156 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AddPermissionPanelComponent } from './add-permission-panel.component';
import { By } from '@angular/platform-browser';
import { SearchService, setupTestBed, SearchConfigurationService } from '@alfresco/adf-core';
import { Observable } from 'rxjs/Observable';
import { fakeAuthorityListResult } from '../../../mock/add-permission.component.mock';
import { ContentTestingModule } from '../../../testing/content.testing.module';
import { DebugElement } from '@angular/core';
describe('AddPermissionPanelComponent', () => {
let fixture: ComponentFixture<AddPermissionPanelComponent>;
let component: AddPermissionPanelComponent;
let element: HTMLElement;
let searchApiService: SearchService;
let debugElement: DebugElement;
setupTestBed({
imports: [ContentTestingModule],
providers: [SearchService, SearchConfigurationService]
});
beforeEach(() => {
fixture = TestBed.createComponent(AddPermissionPanelComponent);
debugElement = fixture.debugElement;
element = fixture.nativeElement;
component = fixture.componentInstance;
fixture.detectChanges();
});
afterEach(() => {
fixture.destroy();
});
function typeWordIntoSearchInput(word: string): void {
let inputDebugElement = debugElement.query(By.css('#searchInput'));
inputDebugElement.nativeElement.value = word;
inputDebugElement.nativeElement.focus();
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
}
it('should be able to render the component', () => {
expect(element.querySelector('#adf-add-permission-type-search')).not.toBeNull();
expect(element.querySelector('#searchInput')).not.toBeNull();
});
it('should show search results when user types something', async(() => {
searchApiService = fixture.componentRef.injector.get(SearchService);
spyOn(searchApiService, 'search').and.returnValue(Observable.of(fakeAuthorityListResult));
expect(element.querySelector('#adf-add-permission-type-search')).not.toBeNull();
expect(element.querySelector('#searchInput')).not.toBeNull();
typeWordIntoSearchInput('a');
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(element.querySelector('#adf-add-permission-authority-results')).not.toBeNull();
expect(element.querySelector('#result_option_0')).not.toBeNull();
});
}));
it('should emit a select event with the selected items when an item is clicked', async(() => {
searchApiService = fixture.componentRef.injector.get(SearchService);
spyOn(searchApiService, 'search').and.returnValue(Observable.of(fakeAuthorityListResult));
component.select.subscribe((items) => {
expect(items).not.toBeNull();
expect(items[0].entry.id).toBeDefined();
expect(items[0].entry.id).not.toBeNull();
expect(items[0].entry.id).toBe(fakeAuthorityListResult.list.entries[0].entry.id);
});
typeWordIntoSearchInput('a');
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
const listElement: DebugElement = fixture.debugElement.query(By.css('#result_option_0'));
expect(listElement).not.toBeNull();
listElement.triggerEventHandler('click', {});
});
}));
it('should show the icon related on the nodeType', async(() => {
searchApiService = fixture.componentRef.injector.get(SearchService);
spyOn(searchApiService, 'search').and.returnValue(Observable.of(fakeAuthorityListResult));
expect(element.querySelector('#adf-add-permission-type-search')).not.toBeNull();
expect(element.querySelector('#searchInput')).not.toBeNull();
typeWordIntoSearchInput('a');
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(element.querySelector('#adf-add-permission-authority-results')).not.toBeNull();
expect(element.querySelector('#result_option_0 #add-person-icon')).toBeDefined();
expect(element.querySelector('#result_option_0 #add-person-icon')).not.toBeNull();
expect(element.querySelector('#result_option_2 #add-group-icon')).toBeDefined();
expect(element.querySelector('#result_option_2 #add-group-icon')).not.toBeNull();
});
}));
it('should clear the search when user delete the search input field', async(() => {
searchApiService = fixture.componentRef.injector.get(SearchService);
spyOn(searchApiService, 'search').and.returnValue(Observable.of(fakeAuthorityListResult));
expect(element.querySelector('#adf-add-permission-type-search')).not.toBeNull();
expect(element.querySelector('#searchInput')).not.toBeNull();
typeWordIntoSearchInput('a');
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(element.querySelector('#adf-add-permission-authority-results')).not.toBeNull();
expect(element.querySelector('#result_option_0')).not.toBeNull();
const clearButton = fixture.debugElement.query(By.css('#adf-permission-clear-input'));
expect(clearButton).not.toBeNull();
clearButton.triggerEventHandler('click', {});
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(element.querySelector('#adf-add-permission-authority-results')).toBeNull();
});
});
}));
it('should remove element from selection when is clicked and already selected', async(() => {
searchApiService = fixture.componentRef.injector.get(SearchService);
spyOn(searchApiService, 'search').and.returnValue(Observable.of(fakeAuthorityListResult));
component.selectedItems.push(fakeAuthorityListResult.list.entries[0]);
component.select.subscribe((items) => {
expect(items).not.toBeNull();
expect(items[0]).toBeUndefined();
expect(component.selectedItems.length).toBe(0);
});
typeWordIntoSearchInput('a');
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
const listElement: DebugElement = fixture.debugElement.query(By.css('#result_option_0'));
expect(listElement).not.toBeNull();
listElement.triggerEventHandler('click', {});
});
}));
});

View File

@@ -0,0 +1,82 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, ViewEncapsulation, EventEmitter, Output, ViewChild } from '@angular/core';
import { SearchPermissionConfigurationService } from './search-config-permission.service';
import { SearchService, SearchConfigurationService } from '@alfresco/adf-core';
import { SearchComponent } from '../../../search/components/search.component';
import { FormControl } from '@angular/forms';
import { debounceTime } from 'rxjs/operators';
import { MinimalNodeEntity } from 'alfresco-js-api';
@Component({
selector: 'adf-add-permission-panel',
templateUrl: './add-permission-panel.component.html',
styleUrls: ['./add-permission-panel.component.scss'],
encapsulation: ViewEncapsulation.None,
providers: [
{ provide: SearchConfigurationService, useClass: SearchPermissionConfigurationService },
SearchService
]
})
export class AddPermissionPanelComponent {
@ViewChild('search')
search: SearchComponent;
@Output()
select: EventEmitter<any> = new EventEmitter();
searchInput: FormControl = new FormControl();
searchedWord = '';
debounceSearch: number = 200;
selectedItems: MinimalNodeEntity[] = [];
constructor() {
this.searchInput.valueChanges
.pipe(
debounceTime(this.debounceSearch)
)
.subscribe((searchValue) => {
this.searchedWord = searchValue;
if (!searchValue) {
this.search.resetResults();
}
});
}
elementClicked(item: MinimalNodeEntity) {
if (this.isAlreadySelected(item)) {
this.selectedItems.splice(this.selectedItems.indexOf(item), 1);
} else {
this.selectedItems.push(item);
}
this.select.emit(this.selectedItems);
}
private isAlreadySelected(item: MinimalNodeEntity): boolean {
return this.selectedItems.indexOf(item) >= 0;
}
clearSearch() {
this.searchedWord = '';
this.selectedItems.splice(0, this.selectedItems.length);
this.search.resetResults();
}
}

View File

@@ -0,0 +1,14 @@
<adf-add-permission-panel
(select)="onSelect($event)">
</adf-add-permission-panel>
<div id="adf-add-permission-actions">
<button mat-button
id="adf-add-permission-action-button"
class="adf-permission-action"
[disabled]="selectedItems?.length === 0"
(click)="applySelection()">
{{'PERMISSION_MANAGER.ADD-PERMISSION.ADD-ACTION' | translate}}
</button>
</div>

View File

@@ -0,0 +1,16 @@
@mixin adf-add-permission-theme($theme) {
$primary: map-get($theme, primary);
.adf {
&-permission-action {
&[disabled] {
opacity: 0.6;
}
&:enabled {
color: mat-color($primary);
}
}
}
}

View File

@@ -0,0 +1,102 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AddPermissionComponent } from './add-permission.component';
import { AddPermissionPanelComponent } from './add-permission-panel.component';
import { By } from '@angular/platform-browser';
import { setupTestBed } from '@alfresco/adf-core';
import { Observable } from 'rxjs/Observable';
import { fakeAuthorityResults } from '../../../mock/add-permission.component.mock';
import { ContentTestingModule } from '../../../testing/content.testing.module';
import { NodePermissionService } from '../../services/node-permission.service';
describe('AddPermissionComponent', () => {
let fixture: ComponentFixture<AddPermissionComponent>;
let element: HTMLElement;
let nodePermissionService: NodePermissionService;
setupTestBed({
imports: [
ContentTestingModule
]
});
beforeEach(() => {
fixture = TestBed.createComponent(AddPermissionComponent);
element = fixture.nativeElement;
nodePermissionService = TestBed.get(NodePermissionService);
fixture.detectChanges();
});
afterEach(() => {
fixture.destroy();
});
it('should be able to render the component', () => {
expect(element.querySelector('#adf-add-permission-type-search')).not.toBeNull();
expect(element.querySelector('#searchInput')).not.toBeNull();
expect(element.querySelector('#adf-add-permission-actions')).not.toBeNull();
const addButton: HTMLButtonElement = <HTMLButtonElement> element.querySelector('#adf-add-permission-action-button');
expect(addButton.disabled).toBeTruthy();
});
it('should enable the ADD button when a selection is sent', async(() => {
const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(By.directive(AddPermissionPanelComponent)).componentInstance;
addPermissionPanelComponent.select.emit(fakeAuthorityResults);
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
const addButton: HTMLButtonElement = <HTMLButtonElement> element.querySelector('#adf-add-permission-action-button');
expect(addButton.disabled).toBeFalsy();
});
}));
it('should emit a success event when the node is updated', async(() => {
fixture.componentInstance.selectedItems = fakeAuthorityResults;
spyOn(nodePermissionService, 'updateNodePermissions').and.returnValue(Observable.of({ id: 'fake-node-id'}));
fixture.componentInstance.success.subscribe((node) => {
expect(node.id).toBe('fake-node-id');
});
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
const addButton: HTMLButtonElement = <HTMLButtonElement> element.querySelector('#adf-add-permission-action-button');
addButton.click();
});
}));
it('should emit an error event when the node update fail', async(() => {
fixture.componentInstance.selectedItems = fakeAuthorityResults;
spyOn(nodePermissionService, 'updateNodePermissions').and.returnValue(Observable.throw({ error: 'errored'}));
fixture.componentInstance.error.subscribe((error) => {
expect(error.error).toBe('errored');
});
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
const addButton: HTMLButtonElement = <HTMLButtonElement> element.querySelector('#adf-add-permission-action-button');
addButton.click();
});
}));
});

View File

@@ -0,0 +1,61 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, ViewEncapsulation, EventEmitter, Input, Output } from '@angular/core';
import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api';
import { NodePermissionService } from '../../services/node-permission.service';
@Component({
selector: 'adf-add-permission',
templateUrl: './add-permission.component.html',
styleUrls: ['./add-permission.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class AddPermissionComponent {
@Input()
nodeId: string;
@Output()
success: EventEmitter<MinimalNodeEntryEntity> = new EventEmitter();
@Output()
error: EventEmitter<any> = new EventEmitter();
selectedItems: MinimalNodeEntity[] = [];
currentNode: MinimalNodeEntryEntity;
currentNodeRoles: string[];
constructor(private nodePermissionService: NodePermissionService) {
}
onSelect(selection: MinimalNodeEntity[]) {
this.selectedItems = selection;
}
applySelection() {
this.nodePermissionService.updateNodePermissions(this.nodeId, this.selectedItems)
.subscribe(
(node) => {
this.success.emit(node);
},
(error) => {
this.error.emit(error);
});
}
}

View File

@@ -0,0 +1,43 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { QueryBody } from 'alfresco-js-api';
import { SearchConfigurationInterface } from '@alfresco/adf-core';
export class SearchPermissionConfigurationService implements SearchConfigurationInterface {
constructor() {
}
public generateQueryBody(searchTerm: string, maxResults: number, skipCount: number): QueryBody {
const defaultQueryBody: QueryBody = {
query: {
query: searchTerm ? `authorityName:${searchTerm}* OR userName:${searchTerm}*` : searchTerm
},
include: ['properties', 'aspectNames'],
paging: {
maxItems: maxResults,
skipCount: skipCount
},
filterQueries: [
/*tslint:disable-next-line */
{ query: "TYPE:'cm:authority'" }]
};
return defaultQueryBody;
}
}

View File

@@ -17,7 +17,7 @@
import { SimpleInheritedPermissionTestComponent } from '../../mock/inherited-permission.component.mock';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { PermissionManagerModule } from '../../index';
import { InheritPermissionDirective } from './inherited-button.directive';
import { NodesApiService, setupTestBed, CoreModule } from '@alfresco/adf-core';
import { Observable } from 'rxjs/Observable';
@@ -33,20 +33,20 @@ describe('InheritPermissionDirective', () => {
setupTestBed({
imports: [
CoreModule.forRoot(),
PermissionManagerModule
CoreModule.forRoot()
],
declarations: [
InheritPermissionDirective,
SimpleInheritedPermissionTestComponent
]
});
beforeEach(() => {
beforeEach(async(() => {
fixture = TestBed.createComponent(SimpleInheritedPermissionTestComponent);
component = fixture.componentInstance;
element = fixture.nativeElement;
nodeService = TestBed.get(NodesApiService);
});
}));
it('should be able to render the simple component', async(() => {
fixture.detectChanges();

View File

@@ -35,15 +35,18 @@ export class InheritPermissionDirective {
@Output()
updated: EventEmitter<MinimalNodeEntryEntity> = new EventEmitter<MinimalNodeEntryEntity>();
@Output()
error: EventEmitter<any> = new EventEmitter<any>();
constructor(private nodeService: NodesApiService) {
}
onInheritPermissionClicked() {
this.nodeService.getNode(this.nodeId).subscribe((node: MinimalNodeEntryEntity) => {
const nodeBody = { permissions : {isInheritanceEnabled : !node.permissions.isInheritanceEnabled} };
this.nodeService.updateNode(this.nodeId, nodeBody, {include: ['permissions'] }).subscribe((nodeUpdated: MinimalNodeEntryEntity) => {
const nodeBody = { permissions: { isInheritanceEnabled: !node.permissions.isInheritanceEnabled } };
this.nodeService.updateNode(this.nodeId, nodeBody, { include: ['permissions'] }).subscribe((nodeUpdated: MinimalNodeEntryEntity) => {
this.updated.emit(nodeUpdated);
});
}, (error) => this.error.emit(error));
});
}

View File

@@ -48,6 +48,13 @@
</ng-template>
</ng-template>
</data-column>
<data-column key="delete">
<ng-template let-entry="$implicit">
<button *ngIf="!entry.row.getValue('isInherited')" mat-icon-button color="primary" (click)="removePermission(entry.row.obj)">
<mat-icon>highlight_off</mat-icon>
</button>
</ng-template>
</data-column>
</data-columns>
</adf-datatable>
</div>

View File

@@ -35,6 +35,9 @@ export class PermissionListComponent implements OnInit {
@Output()
update: EventEmitter<PermissionElement> = new EventEmitter();
@Output()
error: EventEmitter<any> = new EventEmitter();
permissionList: PermissionDisplayModel[];
settableRoles: any[];
actualNode: MinimalNodeEntryEntity;
@@ -82,7 +85,7 @@ export class PermissionListComponent implements OnInit {
saveNewRole(event: any, permissionRow: PermissionDisplayModel) {
let updatedPermissionRole: PermissionElement = this.buildUpdatedPermission(event.value, permissionRow);
this.nodePermissionService.updatePermissionRoles(this.actualNode, updatedPermissionRole)
this.nodePermissionService.updatePermissionRole(this.actualNode, updatedPermissionRole)
.subscribe((node: MinimalNodeEntryEntity) => {
this.update.emit(updatedPermissionRole);
});
@@ -96,4 +99,10 @@ export class PermissionListComponent implements OnInit {
return permissionRole;
}
removePermission(permissionRow: PermissionDisplayModel) {
this.nodePermissionService.removePermission(this.actualNode, permissionRow).subscribe((node) => {
this.update.emit(node);
}, (error) => this.error.emit(error));
}
}