mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-07-31 17:38:28 +00:00
[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:
committed by
Cilibiu Bogdan
parent
0d727a5ffd
commit
5234a875e7
@@ -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';
|
||||
|
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@@ -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) => {
|
||||
|
||||
|
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
});
|
||||
|
@@ -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())
|
||||
]);
|
||||
}
|
||||
|
||||
|
@@ -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();
|
||||
});
|
||||
|
@@ -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))
|
||||
]);
|
||||
|
@@ -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>
|
||||
|
@@ -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']);
|
||||
});
|
||||
|
||||
|
@@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
});
|
||||
|
@@ -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())
|
||||
]);
|
||||
}
|
||||
|
||||
|
@@ -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();
|
||||
});
|
||||
|
@@ -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())
|
||||
]);
|
||||
}
|
||||
|
||||
|
@@ -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(() => {
|
||||
|
@@ -84,7 +84,7 @@ describe('TrashcanComponent', () => {
|
||||
spyOn(component, 'refresh');
|
||||
fixture.detectChanges();
|
||||
|
||||
contentService.restoreNode.next();
|
||||
contentService.nodeRestored.next();
|
||||
|
||||
expect(component.refresh).toHaveBeenCalled();
|
||||
});
|
||||
|
@@ -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 {
|
||||
|
Reference in New Issue
Block a user