mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
[AAE-3966] FE - Disable the upload button when the user doesn't have 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
This commit is contained in:
parent
64ad7923c3
commit
b8cacd3b4e
@ -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. |
|
| 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. |
|
| 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. |
|
| 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
|
## Details
|
||||||
|
|
||||||
|
@ -213,6 +213,10 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
|||||||
@Output()
|
@Output()
|
||||||
showingSearch: EventEmitter<boolean> = new EventEmitter<boolean>();
|
showingSearch: EventEmitter<boolean> = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
/** Emitted when current folder loaded. */
|
||||||
|
@Output()
|
||||||
|
currentFolder: EventEmitter<Node> = new EventEmitter<Node>();
|
||||||
|
|
||||||
@ViewChild('documentList', { static: true })
|
@ViewChild('documentList', { static: true })
|
||||||
documentList: DocumentListComponent;
|
documentList: DocumentListComponent;
|
||||||
|
|
||||||
@ -314,6 +318,12 @@ export class ContentNodeSelectorPanelComponent implements OnInit, OnDestroy {
|
|||||||
this.onFileUploadEvent();
|
this.onFileUploadEvent();
|
||||||
this.resetPagination();
|
this.resetPagination();
|
||||||
this.setSearchScopeToNodes();
|
this.setSearchScopeToNodes();
|
||||||
|
|
||||||
|
this.documentList.$folderNode
|
||||||
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
|
.subscribe((currentNode: Node) => {
|
||||||
|
this.currentFolder.emit(currentNode);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
[showSearch]="data?.showSearch"
|
[showSearch]="data?.showSearch"
|
||||||
[showDropdownSiteList]="data?.showDropdownSiteList"
|
[showDropdownSiteList]="data?.showDropdownSiteList"
|
||||||
[showFilesInResult]="data?.showFilesInResult"
|
[showFilesInResult]="data?.showFilesInResult"
|
||||||
|
(currentFolder)="onCurrentFolder($event)"
|
||||||
(select)="onSelect($event)"
|
(select)="onSelect($event)"
|
||||||
(showingSearch)="onShowingSearch($event)"
|
(showingSearch)="onShowingSearch($event)"
|
||||||
(siteChange)="onSiteChange($event)"
|
(siteChange)="onSiteChange($event)"
|
||||||
@ -29,19 +30,24 @@
|
|||||||
|
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<div>
|
<div>
|
||||||
<adf-upload-button
|
<ng-container *ngIf="data?.showLocalUploadButton">
|
||||||
*ngIf="data?.showLocalUploadButton"
|
<adf-upload-button
|
||||||
[staticTitle]="'FORM.FIELD.UPLOAD' | translate "
|
[staticTitle]="'FORM.FIELD.UPLOAD' | translate "
|
||||||
[multipleFiles]="isMultipleSelection()"
|
[multipleFiles]="isMultipleSelection()"
|
||||||
[rootFolderId]="currentDirectoryId"
|
[rootFolderId]="currentDirectoryId"
|
||||||
[disabled]="disableUploadButton"
|
[disabled]="isNotAllowedToUpload()"
|
||||||
(error)="onError($event)">
|
(error)="onError($event)">
|
||||||
</adf-upload-button>
|
</adf-upload-button>
|
||||||
<ng-container *ngIf="data?.showLocalUploadButton && disableUploadButton">
|
<ng-container>
|
||||||
<div class="adf-content-node-upload-button-warning-message">
|
<div class="adf-content-node-upload-button-warning-message" *ngIf="showingSearch">
|
||||||
<mat-icon>warning</mat-icon>
|
<mat-icon>warning</mat-icon>
|
||||||
<span>{{ 'NODE_SELECTOR.UPLOAD_BUTTON_WARNING_MESSAGE' | translate }}</span>
|
<span>{{ 'NODE_SELECTOR.UPLOAD_BUTTON_SEARCH_WARNING_MESSAGE' | translate }}</span>
|
||||||
</div>
|
</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>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
.mat-dialog-actions {
|
.mat-dialog-actions {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
height: 61px;
|
||||||
background-color: mat-color($background, background);
|
background-color: mat-color($background, background);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -19,10 +19,10 @@ import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
|||||||
import { CUSTOM_ELEMENTS_SCHEMA, EventEmitter } from '@angular/core';
|
import { CUSTOM_ELEMENTS_SCHEMA, EventEmitter } from '@angular/core';
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { ContentNodeSelectorComponent } from './content-node-selector.component';
|
import { ContentNodeSelectorComponent } from './content-node-selector.component';
|
||||||
import { Node } from '@alfresco/js-api';
|
import { Node, NodeEntry } from '@alfresco/js-api';
|
||||||
import { ContentNodeSelectorPanelComponent } from '@alfresco/adf-content-services';
|
import { ContentNodeSelectorPanelComponent, UploadModule } from '@alfresco/adf-content-services';
|
||||||
import { By } from '@angular/platform-browser';
|
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 { of } from 'rxjs';
|
||||||
import { ContentTestingModule } from '../testing/content.testing.module';
|
import { ContentTestingModule } from '../testing/content.testing.module';
|
||||||
import { DocumentListService } from '../document-list/services/document-list.service';
|
import { DocumentListService } from '../document-list/services/document-list.service';
|
||||||
@ -41,13 +41,27 @@ describe('ContentNodeSelectorComponent', () => {
|
|||||||
rowFilter: (shareDataRow: ShareDataRow) => shareDataRow.node.entry.name === 'impossible-name',
|
rowFilter: (shareDataRow: ShareDataRow) => shareDataRow.node.entry.name === 'impossible-name',
|
||||||
imageResolver: () => 'piccolo',
|
imageResolver: () => 'piccolo',
|
||||||
currentFolderId: 'cat-girl-nuku-nuku',
|
currentFolderId: 'cat-girl-nuku-nuku',
|
||||||
|
selectionMode: 'multiple',
|
||||||
showLocalUploadButton: true
|
showLocalUploadButton: true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fakeFolderNodeWithPermission = new NodeEntry({
|
||||||
|
entry: {
|
||||||
|
allowableOperations: [
|
||||||
|
'create',
|
||||||
|
'update'
|
||||||
|
],
|
||||||
|
isFolder: true,
|
||||||
|
name: 'Folder Fake Name',
|
||||||
|
nodeType: 'cm:folder'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
setupTestBed({
|
setupTestBed({
|
||||||
imports: [
|
imports: [
|
||||||
TranslateModule.forRoot(),
|
TranslateModule.forRoot(),
|
||||||
ContentTestingModule
|
ContentTestingModule,
|
||||||
|
UploadModule
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: MAT_DIALOG_DATA, useValue: data }
|
{ provide: MAT_DIALOG_DATA, useValue: data }
|
||||||
@ -58,18 +72,26 @@ describe('ContentNodeSelectorComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const documentListService: DocumentListService = TestBed.inject(DocumentListService);
|
const documentListService: DocumentListService = TestBed.inject(DocumentListService);
|
||||||
const sitesService: SitesService = TestBed.inject(SitesService);
|
const sitesService: SitesService = TestBed.inject(SitesService);
|
||||||
|
|
||||||
spyOn(documentListService, 'getFolder').and.returnValue(of({ list: [] }));
|
spyOn(documentListService, 'getFolder').and.returnValue(of({ list: [] }));
|
||||||
spyOn(documentListService, 'getFolderNode').and.returnValue(of({ entry: {} }));
|
spyOn(documentListService, 'getFolderNode').and.returnValue(of({ entry: {} }));
|
||||||
spyOn(sitesService, 'getSites').and.returnValue(of({ list: { entries: [] } }));
|
spyOn(sitesService, 'getSites').and.returnValue(of({ list: { entries: [] } }));
|
||||||
|
|
||||||
fixture = TestBed.createComponent(ContentNodeSelectorComponent);
|
fixture = TestBed.createComponent(ContentNodeSelectorComponent);
|
||||||
component = fixture.componentInstance;
|
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();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
fixture.destroy();
|
fixture.destroy();
|
||||||
|
TestBed.resetTestingModule();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Data injecting with the "Material dialog way"', () => {
|
describe('Data injecting with the "Material dialog way"', () => {
|
||||||
@ -202,8 +224,10 @@ describe('ContentNodeSelectorComponent', () => {
|
|||||||
expect(adfUploadButton.nativeElement.innerText).toEqual('file_uploadFORM.FIELD.UPLOAD');
|
expect(adfUploadButton.nativeElement.innerText).toEqual('file_uploadFORM.FIELD.UPLOAD');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to disable UploadButton if disableUploadButton set to true', () => {
|
it('should be able to disable UploadButton if showingSearch set to true', () => {
|
||||||
component.disableUploadButton = true;
|
component.showingSearch = true;
|
||||||
|
component.hasAllowableOperations = true;
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button'));
|
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button'));
|
||||||
|
|
||||||
@ -211,8 +235,10 @@ describe('ContentNodeSelectorComponent', () => {
|
|||||||
expect(adfUploadButton.nativeElement.disabled).toBe(true);
|
expect(adfUploadButton.nativeElement.disabled).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to enable UploadButton if disableUploadButton set to false', () => {
|
it('should be able to enable UploadButton if showingSearch set to false', () => {
|
||||||
component.disableUploadButton = false;
|
component.showingSearch = false;
|
||||||
|
component.hasAllowableOperations = true;
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button'));
|
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button'));
|
||||||
|
|
||||||
@ -220,38 +246,69 @@ describe('ContentNodeSelectorComponent', () => {
|
|||||||
expect(adfUploadButton.nativeElement.disabled).toBe(false);
|
expect(adfUploadButton.nativeElement.disabled).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to show warning message if showLocalUploadButton and disableUploadButton set to true', () => {
|
it('should be able to show warning message while searching', () => {
|
||||||
component.disableUploadButton = true;
|
|
||||||
component.data.showLocalUploadButton = true;
|
component.data.showLocalUploadButton = true;
|
||||||
|
component.showingSearch = true;
|
||||||
|
component.hasAllowableOperations = false;
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const warnningMessage = fixture.debugElement.query(By.css('.adf-content-node-upload-button-warning-message span'));
|
const warnningMessage = fixture.debugElement.query(By.css('.adf-content-node-upload-button-warning-message span'));
|
||||||
|
|
||||||
expect(warnningMessage).not.toBeNull();
|
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', () => {
|
it('should not be able to show warning message if it is not in search mode', () => {
|
||||||
component.data.showLocalUploadButton = false;
|
|
||||||
component.disableUploadButton = false;
|
|
||||||
const warnningMessage = fixture.debugElement.query(By.css('.adf-content-node-upload-button-warning-message'));
|
|
||||||
|
|
||||||
expect(warnningMessage).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not be able to show warning message if disableUploadButton set to false', () => {
|
|
||||||
component.data.showLocalUploadButton = true;
|
component.data.showLocalUploadButton = true;
|
||||||
component.disableUploadButton = false;
|
component.showingSearch = false;
|
||||||
const warnningMessage = fixture.debugElement.query(By.css('.adf-content-node-upload-button-warning-message'));
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
const warnningMessage = fixture.debugElement.query(By.css('.adf-content-node-upload-button-warning-message span'));
|
||||||
|
|
||||||
expect(warnningMessage).toBeNull();
|
expect(warnningMessage).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be able to show upload button if showLocalUploadButton set to false', () => {
|
it('should be able to disable UploadButton if user does not have allowable operations', () => {
|
||||||
component.data.showLocalUploadButton = false;
|
component.hasAllowableOperations = false;
|
||||||
fixture.detectChanges();
|
|
||||||
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button span'));
|
|
||||||
|
|
||||||
expect(adfUploadButton).toBeNull();
|
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.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 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 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_PERMISSION_WARNING_MESSAGE');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
import { Component, Inject, ViewEncapsulation } from '@angular/core';
|
import { Component, Inject, ViewEncapsulation } from '@angular/core';
|
||||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
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 { Node } from '@alfresco/js-api';
|
||||||
import { ContentNodeSelectorComponentData } from './content-node-selector.component-data.interface';
|
import { ContentNodeSelectorComponentData } from './content-node-selector.component-data.interface';
|
||||||
import { NodeEntryEvent } from '../document-list/components/node.event';
|
import { NodeEntryEvent } from '../document-list/components/node.event';
|
||||||
@ -34,9 +34,11 @@ export class ContentNodeSelectorComponent {
|
|||||||
buttonActionName: string;
|
buttonActionName: string;
|
||||||
chosenNode: Node[];
|
chosenNode: Node[];
|
||||||
currentDirectoryId: string;
|
currentDirectoryId: string;
|
||||||
disableUploadButton = false;
|
showingSearch = false;
|
||||||
|
hasAllowableOperations = false;
|
||||||
|
|
||||||
constructor(private translation: TranslationService,
|
constructor(private translation: TranslationService,
|
||||||
|
private contentService: ContentService,
|
||||||
private notificationService: NotificationService,
|
private notificationService: NotificationService,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: ContentNodeSelectorComponentData) {
|
@Inject(MAT_DIALOG_DATA) public data: ContentNodeSelectorComponentData) {
|
||||||
this.action = data.actionName ? data.actionName.toUpperCase() : 'CHOOSE';
|
this.action = data.actionName ? data.actionName.toUpperCase() : 'CHOOSE';
|
||||||
@ -89,6 +91,14 @@ export class ContentNodeSelectorComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onShowingSearch(value: boolean) {
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,8 @@
|
|||||||
"SEARCH": "Search",
|
"SEARCH": "Search",
|
||||||
"SEARCH_RESULTS": "Search results",
|
"SEARCH_RESULTS": "Search results",
|
||||||
"SELECT_LOCATION": "Select Location",
|
"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": {
|
"OPERATION": {
|
||||||
"SUCCESS": {
|
"SUCCESS": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user