Skip to content

Commit

Permalink
[AAE-3966] FE - Disable the upload button when the user doesn't have …
Browse files Browse the repository at this point in the history
…permissions in a folder (#6304)

* [AAE-3966] FE - Disable the upload button when the user doesn't have permissions in a folder

* * Handled both error messages while searching

* * Refactored names

* * Fixed unit tests and added some * Updated doc

* * Fixed comment
  • Loading branch information
sivakumar414ram authored Nov 4, 2020
1 parent 64ad792 commit b8cacd3
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Opens a [Content Node Selector](content-node-selector.component.md) in its own
| select | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`Node`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/content-rest-api/docs/Node.md)`[]>` | Emitted when the user has chosen an item. |
| showingSearch | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<boolean>` | Emitted when search is running. |
| siteChange | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<string>` | Emitted when the select site changes. |
| currentFolder | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`Node`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/content-rest-api/docs/Node.md)`[]>` | Emitted when current folder loaded. |

## Details

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
@Output()
showingSearch: EventEmitter<boolean> = new EventEmitter<boolean>();

/** Emitted when current folder loaded. */
@Output()
currentFolder: EventEmitter<Node> = new EventEmitter<Node>();

@ViewChild('documentList', { static: true })
documentList: DocumentListComponent;

Expand Down Expand Up @@ -314,6 +318,12 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
this.onFileUploadEvent();
this.resetPagination();
this.setSearchScopeToNodes();

this.documentList.$folderNode
.pipe(takeUntil(this.onDestroy$))
.subscribe((currentNode: Node) => {
this.currentFolder.emit(currentNode);
});
}

ngOnDestroy() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ <h2>{{title}}</h2>
[showSearch]="data?.showSearch"
[showDropdownSiteList]="data?.showDropdownSiteList"
[showFilesInResult]="data?.showFilesInResult"
(currentFolder)="onCurrentFolder($event)"
(select)="onSelect($event)"
(showingSearch)="onShowingSearch($event)"
(siteChange)="onSiteChange($event)"
Expand All @@ -29,19 +30,24 @@ <h2>{{title}}</h2>

<mat-dialog-actions>
<div>
<adf-upload-button
*ngIf="data?.showLocalUploadButton"
[staticTitle]="'FORM.FIELD.UPLOAD' | translate "
[multipleFiles]="isMultipleSelection()"
[rootFolderId]="currentDirectoryId"
[disabled]="disableUploadButton"
(error)="onError($event)">
</adf-upload-button>
<ng-container *ngIf="data?.showLocalUploadButton && disableUploadButton">
<div class="adf-content-node-upload-button-warning-message">
<mat-icon>warning</mat-icon>
<span>{{ 'NODE_SELECTOR.UPLOAD_BUTTON_WARNING_MESSAGE' | translate }}</span>
</div>
<ng-container *ngIf="data?.showLocalUploadButton">
<adf-upload-button
[staticTitle]="'FORM.FIELD.UPLOAD' | translate "
[multipleFiles]="isMultipleSelection()"
[rootFolderId]="currentDirectoryId"
[disabled]="isNotAllowedToUpload()"
(error)="onError($event)">
</adf-upload-button>
<ng-container>
<div class="adf-content-node-upload-button-warning-message" *ngIf="showingSearch">
<mat-icon>warning</mat-icon>
<span>{{ 'NODE_SELECTOR.UPLOAD_BUTTON_SEARCH_WARNING_MESSAGE' | translate }}</span>
</div>
<div class="adf-content-node-upload-button-warning-message" *ngIf="!hasAllowableOperations && !showingSearch">
<mat-icon>warning</mat-icon>
<span>{{ 'NODE_SELECTOR.UPLOAD_BUTTON_PERMISSION_WARNING_MESSAGE' | translate }}</span>
</div>
</ng-container>
</ng-container>
</div>
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

.mat-dialog-actions {
padding: 8px;
height: 61px;
background-color: mat-color($background, background);
display: flex;
flex-direction: row;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { CUSTOM_ELEMENTS_SCHEMA, EventEmitter } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ContentNodeSelectorComponent } from './content-node-selector.component';
import { Node } from '@alfresco/js-api';
import { ContentNodeSelectorPanelComponent } from '@alfresco/adf-content-services';
import { Node, NodeEntry } from '@alfresco/js-api';
import { ContentNodeSelectorPanelComponent, UploadModule } from '@alfresco/adf-content-services';
import { By } from '@angular/platform-browser';
import { setupTestBed, SitesService } from '@alfresco/adf-core';
import { setupTestBed, SitesService, ContentService } from '@alfresco/adf-core';
import { of } from 'rxjs';
import { ContentTestingModule } from '../testing/content.testing.module';
import { DocumentListService } from '../document-list/services/document-list.service';
Expand All @@ -41,13 +41,27 @@ describe('ContentNodeSelectorComponent', () => {
rowFilter: (shareDataRow: ShareDataRow) => shareDataRow.node.entry.name === 'impossible-name',
imageResolver: () => 'piccolo',
currentFolderId: 'cat-girl-nuku-nuku',
selectionMode: 'multiple',
showLocalUploadButton: true
};

const fakeFolderNodeWithPermission = new NodeEntry({
entry: {
allowableOperations: [
'create',
'update'
],
isFolder: true,
name: 'Folder Fake Name',
nodeType: 'cm:folder'
}
});

setupTestBed({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
ContentTestingModule,
UploadModule
],
providers: [
{ provide: MAT_DIALOG_DATA, useValue: data }
Expand All @@ -58,18 +72,26 @@ describe('ContentNodeSelectorComponent', () => {
beforeEach(() => {
const documentListService: DocumentListService = TestBed.inject(DocumentListService);
const sitesService: SitesService = TestBed.inject(SitesService);

spyOn(documentListService, 'getFolder').and.returnValue(of({ list: [] }));
spyOn(documentListService, 'getFolderNode').and.returnValue(of({ entry: {} }));
spyOn(sitesService, 'getSites').and.returnValue(of({ list: { entries: [] } }));

fixture = TestBed.createComponent(ContentNodeSelectorComponent);
component = fixture.componentInstance;
const contentService = TestBed.inject(ContentService);
spyOn(contentService, 'hasAllowableOperations').and.returnValue(true);
spyOn(contentService, 'getNode').and.returnValue(of(fakeFolderNodeWithPermission));

component.data.showLocalUploadButton = true;
component.hasAllowableOperations = true;
component.showingSearch = false;
fixture.detectChanges();
});

afterEach(() => {
fixture.destroy();
TestBed.resetTestingModule();
});

describe('Data injecting with the "Material dialog way"', () => {
Expand Down Expand Up @@ -202,56 +224,91 @@ describe('ContentNodeSelectorComponent', () => {
expect(adfUploadButton.nativeElement.innerText).toEqual('file_uploadFORM.FIELD.UPLOAD');
});

it('should be able to disable UploadButton if disableUploadButton set to true', () => {
component.disableUploadButton = true;
it('should be able to disable UploadButton if showingSearch set to true', () => {
component.showingSearch = true;
component.hasAllowableOperations = true;

fixture.detectChanges();
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button'));

expect(adfUploadButton).not.toBeNull();
expect(adfUploadButton.nativeElement.disabled).toBe(true);
});

it('should be able to enable UploadButton if disableUploadButton set to false', () => {
component.disableUploadButton = false;
it('should be able to enable UploadButton if showingSearch set to false', () => {
component.showingSearch = false;
component.hasAllowableOperations = true;

fixture.detectChanges();
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button'));

expect(adfUploadButton).not.toBeNull();
expect(adfUploadButton.nativeElement.disabled).toBe(false);
});

it('should be able to show warning message if showLocalUploadButton and disableUploadButton set to true', () => {
component.disableUploadButton = true;
it('should be able to show warning message while searching', () => {
component.data.showLocalUploadButton = true;
component.showingSearch = true;
component.hasAllowableOperations = false;

fixture.detectChanges();
const warnningMessage = fixture.debugElement.query(By.css('.adf-content-node-upload-button-warning-message span'));

expect(warnningMessage).not.toBeNull();
expect(warnningMessage.nativeElement.innerText).toEqual('NODE_SELECTOR.UPLOAD_BUTTON_WARNING_MESSAGE');
expect(warnningMessage.nativeElement.innerText).toEqual('NODE_SELECTOR.UPLOAD_BUTTON_SEARCH_WARNING_MESSAGE');
});

it('should not be able to show warning message if showLocalUploadButton set to false', () => {
component.data.showLocalUploadButton = false;
component.disableUploadButton = false;
const warnningMessage = fixture.debugElement.query(By.css('.adf-content-node-upload-button-warning-message'));
it('should not be able to show warning message if it is not in search mode', () => {
component.data.showLocalUploadButton = true;
component.showingSearch = false;

fixture.detectChanges();
const warnningMessage = fixture.debugElement.query(By.css('.adf-content-node-upload-button-warning-message span'));

expect(warnningMessage).toBeNull();
});

it('should not be able to show warning message if disableUploadButton set to false', () => {
it('should be able to disable UploadButton if user does not have allowable operations', () => {
component.hasAllowableOperations = false;

fixture.detectChanges();
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button'));

expect(adfUploadButton).not.toBeNull();
expect(adfUploadButton.nativeElement.disabled).toBe(true);
});

it('should be able to enable UploadButton if user has allowable operations', () => {
component.hasAllowableOperations = true;

fixture.detectChanges();
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button'));

expect(adfUploadButton).not.toBeNull();
expect(adfUploadButton.nativeElement.disabled).toBe(false);
});

it('should not be able to show warning message if user has allowable operations', () => {
component.data.showLocalUploadButton = true;
component.disableUploadButton = false;
const warnningMessage = fixture.debugElement.query(By.css('.adf-content-node-upload-button-warning-message'));
component.hasAllowableOperations = true;
component.showingSearch = false;

fixture.detectChanges();
const warnningMessage = fixture.debugElement.query(By.css('.adf-content-node-upload-button-warning-message span'));

expect(warnningMessage).toBeNull();
});

it('should not be able to show upload button if showLocalUploadButton set to false', () => {
component.data.showLocalUploadButton = false;
it('should be able to show warning message if user does not have allowable operations', () => {
component.data.showLocalUploadButton = true;
component.hasAllowableOperations = false;
component.showingSearch = false;

fixture.detectChanges();
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button span'));
const warnningMessage = fixture.debugElement.query(By.css('.adf-content-node-upload-button-warning-message span'));

expect(adfUploadButton).toBeNull();
expect(warnningMessage).not.toBeNull();
expect(warnningMessage.nativeElement.innerText).toEqual('NODE_SELECTOR.UPLOAD_BUTTON_PERMISSION_WARNING_MESSAGE');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import { Component, Inject, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { TranslationService, NotificationService } from '@alfresco/adf-core';
import { TranslationService, NotificationService, AllowableOperationsEnum, ContentService } from '@alfresco/adf-core';
import { Node } from '@alfresco/js-api';
import { ContentNodeSelectorComponentData } from './content-node-selector.component-data.interface';
import { NodeEntryEvent } from '../document-list/components/node.event';
Expand All @@ -34,9 +34,11 @@ export class ContentNodeSelectorComponent {
buttonActionName: string;
chosenNode: Node[];
currentDirectoryId: string;
disableUploadButton = false;
showingSearch = false;
hasAllowableOperations = false;

constructor(private translation: TranslationService,
private contentService: ContentService,
private notificationService: NotificationService,
@Inject(MAT_DIALOG_DATA) public data: ContentNodeSelectorComponentData) {
this.action = data.actionName ? data.actionName.toUpperCase() : 'CHOOSE';
Expand Down Expand Up @@ -89,6 +91,14 @@ export class ContentNodeSelectorComponent {
}

onShowingSearch(value: boolean) {
this.disableUploadButton = value;
this.showingSearch = value;
}

onCurrentFolder(currentFolder: Node) {
this.hasAllowableOperations = this.contentService.hasAllowableOperations(currentFolder, AllowableOperationsEnum.CREATE);
}

isNotAllowedToUpload() {
return this.showingSearch || !this.hasAllowableOperations;
}
}
3 changes: 2 additions & 1 deletion lib/content-services/src/lib/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@
"SEARCH": "Search",
"SEARCH_RESULTS": "Search results",
"SELECT_LOCATION": "Select Location",
"UPLOAD_BUTTON_WARNING_MESSAGE": "You can't upload a file whilst a search is still running"
"UPLOAD_BUTTON_SEARCH_WARNING_MESSAGE": "You can't upload a file whilst a search is still running",
"UPLOAD_BUTTON_PERMISSION_WARNING_MESSAGE": "User doesn't have permission to upload content to the folder"
},
"OPERATION": {
"SUCCESS": {
Expand Down

0 comments on commit b8cacd3

Please sign in to comment.