[ACA-1135] spike on deleting nodes from the viewer (#192)

* delete/restore from the viewer

* rename content management service events

* test fixes

* offload node delete/restore to content service

* improve tests
This commit is contained in:
Denys Vuika
2018-02-21 06:00:58 +00:00
committed by Cilibiu Bogdan
parent 0d727a5ffd
commit 5234a875e7
19 changed files with 147 additions and 44 deletions

View File

@@ -122,7 +122,7 @@ export class NodeCopyDirective {
Observable.forkJoin(...batch)
.subscribe(
() => {
this.content.deleteNode.next(null);
this.content.nodeDeleted.next(null);
},
(error) => {
let i18nMessageString = 'APP.MESSAGES.ERRORS.GENERIC';

View File

@@ -229,7 +229,7 @@ describe('NodeDeleteDirective', () => {
});
it('signals files restored', () => {
spyOn(contentService.restoreNode, 'next');
spyOn(contentService.nodeRestored, 'next');
spyOn(nodeApiService, 'restoreNode').and.callFake((id) => {
if (id === '1') {
return Observable.of(null);
@@ -246,7 +246,7 @@ describe('NodeDeleteDirective', () => {
fixture.detectChanges();
element.triggerEventHandler('click', null);
expect(contentService.restoreNode.next).toHaveBeenCalled();
expect(contentService.nodeRestored.next).toHaveBeenCalled();
});
});
});

View File

@@ -74,7 +74,7 @@ export class NodeDeleteDirective {
.subscribe(() => this.restore(processedData.success));
if (processedData.someSucceeded) {
this.content.deleteNode.next(null);
this.content.nodeDeleted.next(null);
}
});
}
@@ -103,7 +103,7 @@ export class NodeDeleteDirective {
}
if (processedData.someSucceeded) {
this.content.restoreNode.next(null);
this.content.nodeRestored.next(null);
}
}
);

View File

@@ -64,7 +64,7 @@ export class NodeMoveDirective {
const [ operationResult, moveResponse ] = result;
this.toastMessage(operationResult, moveResponse);
this.content.moveNode.next(null);
this.content.nodeMoved.next(null);
},
(error) => {
this.toastMessage(error);
@@ -190,7 +190,7 @@ export class NodeMoveDirective {
})
.subscribe(
() => {
this.content.moveNode.next(null);
this.content.nodeMoved.next(null);
},
(error) => {

View File

@@ -25,10 +25,75 @@
import { Subject } from 'rxjs/Rx';
import { Injectable } from '@angular/core';
import { AlfrescoApiService, NotificationService, TranslationService } from '@alfresco/adf-core';
import { Node } from 'alfresco-js-api';
@Injectable()
export class ContentManagementService {
deleteNode = new Subject<string>();
moveNode = new Subject<string>();
restoreNode = new Subject<string>();
nodeDeleted = new Subject<string>();
nodeMoved = new Subject<string>();
nodeRestored = new Subject<string>();
constructor(private api: AlfrescoApiService,
private notification: NotificationService,
private translation: TranslationService) {
}
nodeHasPermission(node: Node, permission: string): boolean {
if (node && permission) {
const allowableOperations = node.allowableOperations || [];
if (allowableOperations.indexOf(permission) > -1) {
return true;
}
}
return false;
}
canDeleteNode(node: Node): boolean {
return this.nodeHasPermission(node, 'delete');
}
async deleteNode(node: Node) {
if (this.canDeleteNode(node)) {
try {
await this.api.nodesApi.deleteNode(node.id);
this.notification
.openSnackMessageAction(
this.translation.instant('APP.MESSAGES.INFO.NODE_DELETION.SINGULAR', { name: node.name }),
this.translation.translate.instant('APP.ACTIONS.UNDO'),
10000
)
.onAction()
.subscribe(() => {
this.restoreNode(node);
});
this.nodeDeleted.next(node.id);
} catch {
this.notification.openSnackMessage(
this.translation.instant('APP.MESSAGES.ERRORS.NODE_DELETION', { name: node.name }),
10000
);
}
}
}
async restoreNode(node: Node) {
if (node) {
try {
await this.api.nodesApi.restoreNode(node.id);
this.nodeRestored.next(node.id);
} catch {
this.notification.openSnackMessage(
this.translation.instant('APP.MESSAGES.ERRORS.NODE_RESTORE', { name: node.name }),
3000
);
}
}
}
}

View File

@@ -114,7 +114,7 @@ describe('Favorites Routed Component', () => {
spyOn(component, 'refresh');
fixture.detectChanges();
contentService.moveNode.next(null);
contentService.nodeMoved.next(null);
expect(component.refresh).toHaveBeenCalled();
});

View File

@@ -62,10 +62,10 @@ export class FavoritesComponent extends PageComponent implements OnInit, OnDestr
ngOnInit() {
this.subscriptions = this.subscriptions.concat([
this.content.deleteNode.subscribe(() => this.refresh()),
this.content.restoreNode.subscribe(() => this.refresh()),
this.content.nodeDeleted.subscribe(() => this.refresh()),
this.content.nodeRestored.subscribe(() => this.refresh()),
this.contentService.folderEdit.subscribe(() => this.refresh()),
this.content.moveNode.subscribe(() => this.refresh())
this.content.nodeMoved.subscribe(() => this.refresh())
]);
}

View File

@@ -194,19 +194,19 @@ describe('FilesComponent', () => {
});
it('calls refresh deleteNode event', () => {
contentManagementService.deleteNode.next();
contentManagementService.nodeDeleted.next();
expect(component.load).toHaveBeenCalled();
});
it('calls refresh moveNode event', () => {
contentManagementService.moveNode.next();
contentManagementService.nodeMoved.next();
expect(component.load).toHaveBeenCalled();
});
it('calls refresh restoreNode event', () => {
contentManagementService.restoreNode.next();
contentManagementService.nodeRestored.next();
expect(component.load).toHaveBeenCalled();
});

View File

@@ -107,9 +107,9 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
nodeActionsService.contentCopied.subscribe((nodes) => this.onContentCopied(nodes)),
contentService.folderCreate.subscribe(() => this.load(false, this.pagination)),
contentService.folderEdit.subscribe(() => this.load(false, this.pagination)),
contentManagementService.deleteNode.subscribe(() => this.load(false, this.pagination)),
contentManagementService.moveNode.subscribe(() => this.load(false, this.pagination)),
contentManagementService.restoreNode.subscribe(() => this.load(false, this.pagination)),
contentManagementService.nodeDeleted.subscribe(() => this.load(false, this.pagination)),
contentManagementService.nodeMoved.subscribe(() => this.load(false, this.pagination)),
contentManagementService.nodeRestored.subscribe(() => this.load(false, this.pagination)),
uploadService.fileUploadComplete.subscribe(file => this.onFileUploadedEvent(file)),
uploadService.fileUploadDeleted.subscribe((file) => this.onFileUploadedEvent(file))
]);

View File

@@ -8,5 +8,14 @@
(showViewerChange)="onVisibilityChanged($event)"
(navigateBefore)="onNavigateBefore()"
(navigateNext)="onNavigateNext()">
<adf-viewer-more-actions>
<button mat-menu-item
[disabled]="!canDeleteFile()"
(click)="deleteFile()">
<mat-icon>delete</mat-icon>
<span>{{ 'APP.ACTIONS.DELETE' | translate }}</span>
</button>
</adf-viewer-more-actions>
</adf-viewer>
</ng-container>

View File

@@ -353,7 +353,9 @@ describe('PreviewComponent', () => {
component.previewLocation = 'personal-files';
await component.displayNode('folder1');
expect(alfrescoApi.nodesApi.getNodeInfo).toHaveBeenCalledWith('folder1');
expect(alfrescoApi.nodesApi.getNodeInfo).toHaveBeenCalledWith(
'folder1', { include: [ 'allowableOperations' ] }
);
expect(router.navigate).toHaveBeenCalledWith(['personal-files', 'folder1']);
});
@@ -368,7 +370,9 @@ describe('PreviewComponent', () => {
component.previewLocation = 'personal-files';
await component.displayNode('folder1');
expect(alfrescoApi.nodesApi.getNodeInfo).toHaveBeenCalledWith('folder1');
expect(alfrescoApi.nodesApi.getNodeInfo).toHaveBeenCalledWith(
'folder1', { include: [ 'allowableOperations' ] }
);
expect(router.navigate).toHaveBeenCalledWith(['personal-files', 'folder1']);
});
@@ -381,7 +385,9 @@ describe('PreviewComponent', () => {
component.previewLocation = 'personal-files';
await component.displayNode('folder1');
expect(alfrescoApi.nodesApi.getNodeInfo).toHaveBeenCalledWith('folder1');
expect(alfrescoApi.nodesApi.getNodeInfo).toHaveBeenCalledWith(
'folder1', { include: [ 'allowableOperations' ] }
);
expect(router.navigate).toHaveBeenCalledWith(['personal-files', 'folder1']);
});
@@ -399,7 +405,9 @@ describe('PreviewComponent', () => {
component.previewLocation = 'personal-files';
await component.displayNode('folder1');
expect(alfrescoApi.nodesApi.getNodeInfo).toHaveBeenCalledWith('folder1');
expect(alfrescoApi.nodesApi.getNodeInfo).toHaveBeenCalledWith(
'folder1', { include: [ 'allowableOperations' ] }
);
expect(router.navigate).toHaveBeenCalledWith(['personal-files', 'folder1']);
});

View File

@@ -27,6 +27,7 @@ import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { AlfrescoApiService, UserPreferencesService, ObjectUtils } from '@alfresco/adf-core';
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
import { ContentManagementService } from '../../common/services/content-management.service';
@Component({
selector: 'app-preview',
@@ -53,7 +54,8 @@ export class PreviewComponent implements OnInit {
constructor(private router: Router,
private route: ActivatedRoute,
private apiService: AlfrescoApiService,
private preferences: UserPreferencesService) {
private preferences: UserPreferencesService,
private content: ContentManagementService) {
}
ngOnInit() {
@@ -90,7 +92,9 @@ export class PreviewComponent implements OnInit {
async displayNode(id: string) {
if (id) {
try {
this.node = await this.apiService.nodesApi.getNodeInfo(id);
this.node = await this.apiService.nodesApi.getNodeInfo(id, {
include: [ 'allowableOperations']
});
if (this.node && this.node.isFile) {
const nearest = await this.getNearestNodes(this.node.id, this.node.parentId);
@@ -315,4 +319,16 @@ export class PreviewComponent implements OnInit {
}
return path;
}
canDeleteFile(): boolean {
return this.content.canDeleteNode(this.node);
}
async deleteFile() {
try {
await this.content.deleteNode(this.node);
this.onVisibilityChanged(false);
} catch {
}
}
}

View File

@@ -92,7 +92,7 @@ describe('RecentFiles Routed Component', () => {
it('should reload nodes on onDeleteNode event', () => {
fixture.detectChanges();
contentService.deleteNode.next();
contentService.nodeDeleted.next();
expect(component.refresh).toHaveBeenCalled();
});
@@ -100,7 +100,7 @@ describe('RecentFiles Routed Component', () => {
it('should reload on onRestoreNode event', () => {
fixture.detectChanges();
contentService.restoreNode.next();
contentService.nodeRestored.next();
expect(component.refresh).toHaveBeenCalled();
});
@@ -108,7 +108,7 @@ describe('RecentFiles Routed Component', () => {
it('should reload on move node event', () => {
fixture.detectChanges();
contentService.moveNode.next();
contentService.nodeMoved.next();
expect(component.refresh).toHaveBeenCalled();
});

View File

@@ -60,9 +60,9 @@ export class RecentFilesComponent extends PageComponent implements OnInit, OnDes
ngOnInit() {
this.subscriptions = this.subscriptions.concat([
this.content.deleteNode.subscribe(() => this.refresh()),
this.content.moveNode.subscribe(() => this.refresh()),
this.content.restoreNode.subscribe(() => this.refresh())
this.content.nodeDeleted.subscribe(() => this.refresh()),
this.content.nodeMoved.subscribe(() => this.refresh()),
this.content.nodeRestored.subscribe(() => this.refresh())
]);
}

View File

@@ -89,7 +89,7 @@ describe('SharedFilesComponent', () => {
it('should refresh on deleteNode event', () => {
fixture.detectChanges();
contentService.deleteNode.next();
contentService.nodeDeleted.next();
expect(component.refresh).toHaveBeenCalled();
});
@@ -97,7 +97,7 @@ describe('SharedFilesComponent', () => {
it('should refresh on restoreNode event', () => {
fixture.detectChanges();
contentService.restoreNode.next();
contentService.nodeRestored.next();
expect(component.refresh).toHaveBeenCalled();
});
@@ -105,7 +105,7 @@ describe('SharedFilesComponent', () => {
it('should reload on move node event', () => {
fixture.detectChanges();
contentService.moveNode.next();
contentService.nodeMoved.next();
expect(component.refresh).toHaveBeenCalled();
});

View File

@@ -60,9 +60,9 @@ export class SharedFilesComponent extends PageComponent implements OnInit, OnDes
ngOnInit() {
this.subscriptions = this.subscriptions.concat([
this.content.deleteNode.subscribe(() => this.refresh()),
this.content.moveNode.subscribe(() => this.refresh()),
this.content.restoreNode.subscribe(() => this.refresh())
this.content.nodeDeleted.subscribe(() => this.refresh()),
this.content.nodeMoved.subscribe(() => this.refresh()),
this.content.nodeRestored.subscribe(() => this.refresh())
]);
}

View File

@@ -23,13 +23,14 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { TestBed, async } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { ContentService, AppConfigService } from '@alfresco/adf-core';
import { CoreModule, ContentService, AppConfigService } from '@alfresco/adf-core';
import { BrowsingFilesService } from '../../common/services/browsing-files.service';
import { SidenavComponent } from './sidenav.component';
import { CommonModule } from './../../common/common.module';
describe('SidenavComponent', () => {
let fixture;
@@ -50,11 +51,15 @@ describe('SidenavComponent', () => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
CommonModule
CoreModule
],
declarations: [
SidenavComponent
]
],
providers: [
BrowsingFilesService
],
schemas: [ NO_ERRORS_SCHEMA ]
})
.compileComponents()
.then(() => {

View File

@@ -84,7 +84,7 @@ describe('TrashcanComponent', () => {
spyOn(component, 'refresh');
fixture.detectChanges();
contentService.restoreNode.next();
contentService.nodeRestored.next();
expect(component.refresh).toHaveBeenCalled();
});

View File

@@ -48,7 +48,7 @@ export class TrashcanComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.subscriptions.push(this.contentManagementService.restoreNode.subscribe(() => this.refresh()));
this.subscriptions.push(this.contentManagementService.nodeRestored.subscribe(() => this.refresh()));
}
refresh(): void {