diff --git a/src/app/components/info-drawer/library-metadata-tab/library-metadata-form.component.html b/src/app/components/info-drawer/library-metadata-tab/library-metadata-form.component.html index f41910ec0..4ea4e8c28 100644 --- a/src/app/components/info-drawer/library-metadata-tab/library-metadata-form.component.html +++ b/src/app/components/info-drawer/library-metadata-tab/library-metadata-form.component.html @@ -85,6 +85,7 @@ + {{ 'LIBRARY.HINTS.SITE_TITLE_EXISTS' | translate }} {{ 'LIBRARY.ERRORS.TITLE_TOO_LONG' | translate }} diff --git a/src/app/components/info-drawer/library-metadata-tab/library-metadata-form.component.spec.ts b/src/app/components/info-drawer/library-metadata-tab/library-metadata-form.component.spec.ts index 9b54f8c65..ab7652fb6 100644 --- a/src/app/components/info-drawer/library-metadata-tab/library-metadata-form.component.spec.ts +++ b/src/app/components/info-drawer/library-metadata-tab/library-metadata-form.component.spec.ts @@ -23,16 +23,23 @@ * along with Alfresco. If not, see . */ 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 { UpdateLibraryAction } from '../../../store/actions'; import { AppTestingModule } from '../../../testing/app-testing.module'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { Site, SiteBody } from 'alfresco-js-api'; +import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-core'; describe('LibraryMetadataFormComponent', () => { let fixture: ComponentFixture; let component: LibraryMetadataFormComponent; + let alfrescoApiService: AlfrescoApiService; const storeMock = { dispatch: jasmine.createSpy('dispatch') }; @@ -41,12 +48,16 @@ describe('LibraryMetadataFormComponent', () => { TestBed.configureTestingModule({ imports: [AppTestingModule], declarations: [LibraryMetadataFormComponent], - providers: [{ provide: Store, useValue: storeMock }], + providers: [ + { provide: Store, useValue: storeMock }, + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock } + ], schemas: [NO_ERRORS_SCHEMA] }); fixture = TestBed.createComponent(LibraryMetadataFormComponent); component = fixture.componentInstance; + alfrescoApiService = TestBed.get(AlfrescoApiService); }); afterEach(() => { @@ -211,4 +222,98 @@ describe('LibraryMetadataFormComponent', () => { 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: { + 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: { + 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: { + id: 'libraryId', + ...siteEntryModel + } + }; + + fixture.detectChanges(); + component.form.controls.title.setValue('some-name'); + fixture.detectChanges(); + + tick(500); + expect(component.libraryTitleExists).toBe(false); + })); }); diff --git a/src/app/components/info-drawer/library-metadata-tab/library-metadata-form.component.ts b/src/app/components/info-drawer/library-metadata-tab/library-metadata-form.component.ts index e687bb8f1..c9a707d9e 100644 --- a/src/app/components/info-drawer/library-metadata-tab/library-metadata-form.component.ts +++ b/src/app/components/info-drawer/library-metadata-tab/library-metadata-form.component.ts @@ -23,22 +23,27 @@ * along with Alfresco. If not, see . */ -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 { SiteEntry } from 'alfresco-js-api'; +import { SiteEntry, SitePaging } from 'alfresco-js-api'; import { Store } from '@ngrx/store'; import { UpdateLibraryAction } from '../../../store/actions'; 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({ selector: 'app-library-metadata-form', templateUrl: './library-metadata-form.component.html' }) -export class LibraryMetadataFormComponent implements OnInit, OnChanges { +export class LibraryMetadataFormComponent + implements OnInit, OnChanges, OnDestroy { @Input() node: SiteEntry; edit: boolean; + libraryTitleExists = false; libraryType = [ { value: 'PUBLIC', label: 'LIBRARY.VISIBILITY.PUBLIC' }, @@ -56,7 +61,12 @@ export class LibraryMetadataFormComponent implements OnInit, OnChanges { visibility: new FormControl(this.libraryType[0].value) }); - constructor(protected store: Store) {} + onDestroy$: Subject = new Subject(); + + constructor( + private alfrescoApiService: AlfrescoApiService, + protected store: Store + ) {} get canUpdateLibrary() { return ( @@ -79,6 +89,32 @@ export class LibraryMetadataFormComponent implements OnInit, OnChanges { ngOnInit() { 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() { @@ -101,4 +137,16 @@ export class LibraryMetadataFormComponent implements OnInit, OnChanges { visibility: entry.visibility }); } + + private findLibraryByTitle(libraryTitle: string): Observable { + return from( + this.alfrescoApiService + .getInstance() + .core.queriesApi.findSites(libraryTitle, { + maxItems: 1, + fields: ['title'] + }) + .catch(() => ({ list: { entries: [] } })) + ); + } }