[ACA-1957] Library metadata - check title uniqueness (#767)

* add hint element

* check title uniqueness

* update tests
This commit is contained in:
Cilibiu Bogdan
2018-10-30 21:10:56 +02:00
committed by Denys Vuika
parent 8d68ada078
commit b5cf1bf18d
3 changed files with 160 additions and 6 deletions

View File

@@ -85,6 +85,7 @@
<input matInput cdkFocusInitial required placeholder="{{ 'LIBRARY.DIALOG.FORM.NAME' | translate }}" <input matInput cdkFocusInitial required placeholder="{{ 'LIBRARY.DIALOG.FORM.NAME' | translate }}"
formControlName="title"> formControlName="title">
<mat-hint *ngIf="libraryTitleExists">{{ 'LIBRARY.HINTS.SITE_TITLE_EXISTS' | translate }}</mat-hint>
<mat-error *ngIf="form.controls['title'].hasError('maxlength')"> <mat-error *ngIf="form.controls['title'].hasError('maxlength')">
{{ 'LIBRARY.ERRORS.TITLE_TOO_LONG' | translate }} {{ 'LIBRARY.ERRORS.TITLE_TOO_LONG' | translate }}
</mat-error> </mat-error>

View File

@@ -23,16 +23,23 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { LibraryMetadataFormComponent } from './library-metadata-form.component'; import { LibraryMetadataFormComponent } from './library-metadata-form.component';
import { TestBed, ComponentFixture } from '@angular/core/testing'; import {
TestBed,
ComponentFixture,
fakeAsync,
tick
} from '@angular/core/testing';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { UpdateLibraryAction } from '../../../store/actions'; import { UpdateLibraryAction } from '../../../store/actions';
import { AppTestingModule } from '../../../testing/app-testing.module'; import { AppTestingModule } from '../../../testing/app-testing.module';
import { NO_ERRORS_SCHEMA } from '@angular/core'; import { NO_ERRORS_SCHEMA } from '@angular/core';
import { Site, SiteBody } from 'alfresco-js-api'; import { Site, SiteBody } from 'alfresco-js-api';
import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-core';
describe('LibraryMetadataFormComponent', () => { describe('LibraryMetadataFormComponent', () => {
let fixture: ComponentFixture<LibraryMetadataFormComponent>; let fixture: ComponentFixture<LibraryMetadataFormComponent>;
let component: LibraryMetadataFormComponent; let component: LibraryMetadataFormComponent;
let alfrescoApiService: AlfrescoApiService;
const storeMock = { const storeMock = {
dispatch: jasmine.createSpy('dispatch') dispatch: jasmine.createSpy('dispatch')
}; };
@@ -41,12 +48,16 @@ describe('LibraryMetadataFormComponent', () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [AppTestingModule], imports: [AppTestingModule],
declarations: [LibraryMetadataFormComponent], declarations: [LibraryMetadataFormComponent],
providers: [{ provide: Store, useValue: storeMock }], providers: [
{ provide: Store, useValue: storeMock },
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }
],
schemas: [NO_ERRORS_SCHEMA] schemas: [NO_ERRORS_SCHEMA]
}); });
fixture = TestBed.createComponent(LibraryMetadataFormComponent); fixture = TestBed.createComponent(LibraryMetadataFormComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
alfrescoApiService = TestBed.get(AlfrescoApiService);
}); });
afterEach(() => { afterEach(() => {
@@ -211,4 +222,98 @@ describe('LibraryMetadataFormComponent', () => {
expect(component.form.value).toEqual(siteEntryModel); expect(component.form.value).toEqual(siteEntryModel);
}); });
it('should warn if library name input is used by another library', fakeAsync(() => {
const title = 'some-title';
spyOn(
alfrescoApiService.getInstance().core.queriesApi,
'findSites'
).and.returnValue(
Promise.resolve({
list: { entries: [{ entry: { title } }] }
})
);
const siteEntryModel = {
title: 'libraryTitle',
description: 'description',
visibility: 'PRIVATE'
};
component.node = {
entry: <Site>{
id: 'libraryId',
...siteEntryModel
}
};
fixture.detectChanges();
component.form.controls.title.setValue(title);
fixture.detectChanges();
tick(500);
expect(component.libraryTitleExists).toBe(true);
}));
it('should not warn if library name input is the same with library node data', fakeAsync(() => {
spyOn(
alfrescoApiService.getInstance().core.queriesApi,
'findSites'
).and.returnValue(
Promise.resolve({
list: { entries: [{ entry: { title: 'libraryTitle' } }] }
})
);
const siteEntryModel = {
title: 'libraryTitle',
description: 'description',
visibility: 'PRIVATE'
};
component.node = {
entry: <Site>{
id: 'libraryId',
...siteEntryModel
}
};
fixture.detectChanges();
component.form.controls.title.setValue('libraryTitle');
fixture.detectChanges();
tick(500);
expect(component.libraryTitleExists).toBe(false);
}));
it('should not warn if library name is unique', fakeAsync(() => {
spyOn(
alfrescoApiService.getInstance().core.queriesApi,
'findSites'
).and.returnValue(
Promise.resolve({
list: { entries: [] }
})
);
const siteEntryModel = {
title: 'libraryTitle',
description: 'description',
visibility: 'PRIVATE'
};
component.node = {
entry: <Site>{
id: 'libraryId',
...siteEntryModel
}
};
fixture.detectChanges();
component.form.controls.title.setValue('some-name');
fixture.detectChanges();
tick(500);
expect(component.libraryTitleExists).toBe(false);
}));
}); });

View File

@@ -23,22 +23,27 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { Component, Input, OnInit, OnChanges } from '@angular/core'; import { Component, Input, OnInit, OnChanges, OnDestroy } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms'; import { FormGroup, FormControl, Validators } from '@angular/forms';
import { SiteEntry } from 'alfresco-js-api'; import { SiteEntry, SitePaging } from 'alfresco-js-api';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { UpdateLibraryAction } from '../../../store/actions'; import { UpdateLibraryAction } from '../../../store/actions';
import { AppStore } from '../../../store/states/app.state'; import { AppStore } from '../../../store/states/app.state';
import { debounceTime, mergeMap, takeUntil } from 'rxjs/operators';
import { AlfrescoApiService } from '@alfresco/adf-core';
import { Observable, from, Subject } from 'rxjs';
@Component({ @Component({
selector: 'app-library-metadata-form', selector: 'app-library-metadata-form',
templateUrl: './library-metadata-form.component.html' templateUrl: './library-metadata-form.component.html'
}) })
export class LibraryMetadataFormComponent implements OnInit, OnChanges { export class LibraryMetadataFormComponent
implements OnInit, OnChanges, OnDestroy {
@Input() @Input()
node: SiteEntry; node: SiteEntry;
edit: boolean; edit: boolean;
libraryTitleExists = false;
libraryType = [ libraryType = [
{ value: 'PUBLIC', label: 'LIBRARY.VISIBILITY.PUBLIC' }, { value: 'PUBLIC', label: 'LIBRARY.VISIBILITY.PUBLIC' },
@@ -56,7 +61,12 @@ export class LibraryMetadataFormComponent implements OnInit, OnChanges {
visibility: new FormControl(this.libraryType[0].value) visibility: new FormControl(this.libraryType[0].value)
}); });
constructor(protected store: Store<AppStore>) {} onDestroy$: Subject<boolean> = new Subject<boolean>();
constructor(
private alfrescoApiService: AlfrescoApiService,
protected store: Store<AppStore>
) {}
get canUpdateLibrary() { get canUpdateLibrary() {
return ( return (
@@ -79,6 +89,32 @@ export class LibraryMetadataFormComponent implements OnInit, OnChanges {
ngOnInit() { ngOnInit() {
this.updateForm(this.node); this.updateForm(this.node);
this.form.controls['title'].valueChanges
.pipe(
debounceTime(300),
mergeMap(title => this.findLibraryByTitle(title)),
takeUntil(this.onDestroy$)
)
.subscribe(result => {
const { entries } = result.list;
if (entries.length) {
if (this.form.controls.title.value === this.node.entry.title) {
this.libraryTitleExists = false;
} else {
this.libraryTitleExists =
this.form.controls.title.value === entries[0].entry.title;
}
} else {
this.libraryTitleExists = false;
}
});
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
} }
ngOnChanges() { ngOnChanges() {
@@ -101,4 +137,16 @@ export class LibraryMetadataFormComponent implements OnInit, OnChanges {
visibility: entry.visibility visibility: entry.visibility
}); });
} }
private findLibraryByTitle(libraryTitle: string): Observable<SitePaging> {
return from(
this.alfrescoApiService
.getInstance()
.core.queriesApi.findSites(libraryTitle, {
maxItems: 1,
fields: ['title']
})
.catch(() => ({ list: { entries: [] } }))
);
}
} }