[ADF-4268] Info drawer fixes (#4709)

* show error popups

* proper error handling

* update tests

* update code as per review

* remove old implementation

* remove old code
This commit is contained in:
Denys Vuika
2019-05-13 07:24:49 +01:00
committed by Eugenio Romano
parent fc9f04c6c6
commit bbea17fe37
5 changed files with 86 additions and 34 deletions

View File

@@ -33,6 +33,8 @@ describe('ContentMetadataComponent', () => {
let component: ContentMetadataComponent;
let fixture: ComponentFixture<ContentMetadataComponent>;
let contentMetadataService: ContentMetadataService;
let updateService: CardViewUpdateService;
let nodesApiService: NodesApiService;
let node: Node;
let folderNode: Node;
const preset = 'custom-preset';
@@ -46,6 +48,9 @@ describe('ContentMetadataComponent', () => {
fixture = TestBed.createComponent(ContentMetadataComponent);
component = fixture.componentInstance;
contentMetadataService = TestBed.get(ContentMetadataService);
updateService = TestBed.get(CardViewUpdateService);
nodesApiService = TestBed.get(NodesApiService);
node = <Node> {
id: 'node-id',
aspectNames: [],
@@ -104,9 +109,7 @@ describe('ContentMetadataComponent', () => {
describe('Saving', () => {
it('should save the node on itemUpdate', () => {
const property = <CardViewBaseItemModel> { key: 'property-key', value: 'original-value' },
updateService: CardViewUpdateService = fixture.debugElement.injector.get(CardViewUpdateService),
nodesApiService: NodesApiService = TestBed.get(NodesApiService);
const property = <CardViewBaseItemModel> { key: 'property-key', value: 'original-value' };
spyOn(nodesApiService, 'updateNode').and.callThrough();
updateService.update(property, 'updated-value');
@@ -117,10 +120,8 @@ describe('ContentMetadataComponent', () => {
});
it('should update the node on successful save', async(() => {
const property = <CardViewBaseItemModel> { key: 'property-key', value: 'original-value' },
updateService: CardViewUpdateService = fixture.debugElement.injector.get(CardViewUpdateService),
nodesApiService: NodesApiService = TestBed.get(NodesApiService),
expectedNode = Object.assign({}, node, { name: 'some-modified-value' });
const property = <CardViewBaseItemModel> { key: 'property-key', value: 'original-value' };
const expectedNode = Object.assign({}, node, { name: 'some-modified-value' });
spyOn(nodesApiService, 'updateNode').and.callFake(() => {
return of(expectedNode);
@@ -134,10 +135,8 @@ describe('ContentMetadataComponent', () => {
}));
it('should throw error on unsuccessful save', () => {
const property = <CardViewBaseItemModel> { key: 'property-key', value: 'original-value' },
updateService: CardViewUpdateService = fixture.debugElement.injector.get(CardViewUpdateService),
nodesApiService: NodesApiService = TestBed.get(NodesApiService),
logService: LogService = TestBed.get(LogService);
const property = <CardViewBaseItemModel> { key: 'property-key', value: 'original-value' };
const logService: LogService = TestBed.get(LogService);
spyOn(nodesApiService, 'updateNode').and.callFake(() => {
return throwError(new Error('My bad'));
@@ -147,6 +146,23 @@ describe('ContentMetadataComponent', () => {
expect(logService.error).toHaveBeenCalledWith(new Error('My bad'));
});
it('should raise error message', (done) => {
const property = <CardViewBaseItemModel> { key: 'property-key', value: 'original-value' };
const sub = contentMetadataService.error.subscribe((err) => {
expect(err.statusCode).toBe(0);
expect(err.message).toBe('METADATA.ERRORS.GENERIC');
sub.unsubscribe();
done();
});
spyOn(nodesApiService, 'updateNode').and.callFake(() => {
return throwError(new Error('My bad'));
});
updateService.update(property, 'updated-value');
});
});
describe('Properties loading', () => {

View File

@@ -17,11 +17,11 @@
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { Node } from '@alfresco/js-api';
import { Observable, Subscription } from 'rxjs';
import { CardViewItem, NodesApiService, LogService, CardViewUpdateService, AlfrescoApiService } from '@alfresco/adf-core';
import { Observable, Subject, of } from 'rxjs';
import { CardViewItem, NodesApiService, LogService, CardViewUpdateService, AlfrescoApiService, TranslationService } from '@alfresco/adf-core';
import { ContentMetadataService } from '../../services/content-metadata.service';
import { CardViewGroup } from '../../interfaces/content-metadata.interfaces';
import { switchMap } from 'rxjs/operators';
import { switchMap, takeUntil, catchError } from 'rxjs/operators';
@Component({
selector: 'adf-content-metadata',
@@ -31,6 +31,9 @@ import { switchMap } from 'rxjs/operators';
encapsulation: ViewEncapsulation.None
})
export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
protected onDestroy$ = new Subject<boolean>();
/** (required) The node entity to fetch metadata about */
@Input()
node: Node;
@@ -67,32 +70,62 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
basicProperties$: Observable<CardViewItem[]>;
groupedProperties$: Observable<CardViewGroup[]>;
disposableNodeUpdate: Subscription;
constructor(
private contentMetadataService: ContentMetadataService,
private cardViewUpdateService: CardViewUpdateService,
private nodesApiService: NodesApiService,
private logService: LogService,
private alfrescoApiService: AlfrescoApiService
private alfrescoApiService: AlfrescoApiService,
private translationService: TranslationService
) {}
ngOnInit() {
this.disposableNodeUpdate = this.cardViewUpdateService.itemUpdated$
this.cardViewUpdateService.itemUpdated$
.pipe(
switchMap(this.saveNode.bind(this))
switchMap((changes) =>
this.saveNode(changes).pipe(
catchError((err) => {
this.handleUpdateError(err);
return of(null);
})
)
),
takeUntil(this.onDestroy$)
)
.subscribe(
(updatedNode) => {
Object.assign(this.node, updatedNode);
this.alfrescoApiService.nodeUpdated.next(this.node);
},
(error) => this.logService.error(error)
if (updatedNode) {
Object.assign(this.node, updatedNode);
this.alfrescoApiService.nodeUpdated.next(this.node);
}
}
);
this.loadProperties(this.node);
}
protected handleUpdateError(error: Error) {
this.logService.error(error);
let statusCode = 0;
try {
statusCode = JSON.parse(error.message).error.statusCode;
} catch {}
let message = `METADATA.ERRORS.${statusCode}`;
if (this.translationService.instant(message) === message) {
message = 'METADATA.ERRORS.GENERIC';
}
this.contentMetadataService.error.next({
statusCode,
message
});
}
ngOnChanges(changes: SimpleChanges) {
if (changes.node && !changes.node.firstChange) {
this.loadProperties(changes.node.currentValue);
@@ -119,7 +152,8 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
}
ngOnDestroy() {
this.disposableNodeUpdate.unsubscribe();
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
public canExpandTheCard(group: CardViewGroup): boolean {

View File

@@ -18,7 +18,7 @@
import { Injectable } from '@angular/core';
import { Node } from '@alfresco/js-api';
import { BasicPropertiesService } from './basic-properties.service';
import { Observable, of, iif } from 'rxjs';
import { Observable, of, iif, Subject } from 'rxjs';
import { PropertyGroupTranslatorService } from './property-groups-translator.service';
import { CardViewItem } from '@alfresco/adf-core';
import { CardViewGroup, OrganisedPropertyGroup } from '../interfaces/content-metadata.interfaces';
@@ -31,6 +31,8 @@ import { map, switchMap } from 'rxjs/operators';
})
export class ContentMetadataService {
error = new Subject<{ statusCode: number, message: string }>();
constructor(private basicPropertiesService: BasicPropertiesService,
private contentMetadataConfigFactory: ContentMetadataConfigFactory,
private propertyGroupTranslatorService: PropertyGroupTranslatorService,

View File

@@ -277,6 +277,11 @@
"CREATED_DATE": "Created Date",
"MODIFIER": "Modifier",
"MODIFIED_DATE": "Modified Date"
},
"ERRORS": {
"GENERIC": "Error updating property",
"409": "Duplicate child name not allowed [409]",
"422": "Invalid property value"
}
},
"SHARE": {