[ACA-4454] The create library button should get disabled after being clicked once (#7046)

This commit is contained in:
Dharan
2021-05-24 13:52:25 +05:30
committed by GitHub
parent a5c8586184
commit 4c1e462364
4 changed files with 73 additions and 44 deletions

View File

@@ -87,7 +87,7 @@
color="primary" color="primary"
mat-button mat-button
(click)="submit()" (click)="submit()"
[disabled]="!form.valid" [disabled]="!form.valid || disableCreateButton"
data-automation-id="create-library-id" data-automation-id="create-library-id"
> >
{{ 'LIBRARY.DIALOG.CREATE' | translate }} {{ 'LIBRARY.DIALOG.CREATE' | translate }}

View File

@@ -16,16 +16,19 @@
*/ */
import { LibraryDialogComponent } from './library.dialog'; import { LibraryDialogComponent } from './library.dialog';
import { TestBed, fakeAsync, tick, flush } from '@angular/core/testing'; import { TestBed, fakeAsync, tick, flush, ComponentFixture, flushMicrotasks } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core'; import { NO_ERRORS_SCHEMA } from '@angular/core';
import { MatDialogRef } from '@angular/material/dialog'; import { MatDialogRef } from '@angular/material/dialog';
import { AlfrescoApiService, setupTestBed } from '@alfresco/adf-core'; import { AlfrescoApiService, setupTestBed, SitesService } from '@alfresco/adf-core';
import { ContentTestingModule } from '../../testing/content.testing.module'; import { ContentTestingModule } from '../../testing/content.testing.module';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { of, throwError } from 'rxjs';
import { delay } from 'rxjs/operators';
describe('LibraryDialogComponent', () => { describe('LibraryDialogComponent', () => {
let fixture; let fixture: ComponentFixture<LibraryDialogComponent>;
let component; let component: LibraryDialogComponent;
let sitesService: SitesService;
let alfrescoApi; let alfrescoApi;
let findSitesSpy; let findSitesSpy;
const findSitesResponse = { list: { entries: [] } }; const findSitesResponse = { list: { entries: [] } };
@@ -48,6 +51,7 @@ describe('LibraryDialogComponent', () => {
fixture = TestBed.createComponent(LibraryDialogComponent); fixture = TestBed.createComponent(LibraryDialogComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
alfrescoApi = TestBed.inject(AlfrescoApiService); alfrescoApi = TestBed.inject(AlfrescoApiService);
sitesService = TestBed.inject(SitesService);
findSitesSpy = spyOn(alfrescoApi.getInstance().core.queriesApi, 'findSites'); findSitesSpy = spyOn(alfrescoApi.getInstance().core.queriesApi, 'findSites');
}); });
@@ -57,8 +61,8 @@ describe('LibraryDialogComponent', () => {
it('should set library id automatically on title input', fakeAsync(() => { it('should set library id automatically on title input', fakeAsync(() => {
findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse)); findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse));
spyOn(alfrescoApi.sitesApi, 'getSite').and.callFake(() => { spyOn(sitesService, 'getSite').and.callFake(() => {
return Promise.reject(); return throwError('error');
}); });
fixture.detectChanges(); fixture.detectChanges();
@@ -72,8 +76,8 @@ describe('LibraryDialogComponent', () => {
it('should translate library title space character to dash for library id', fakeAsync(() => { it('should translate library title space character to dash for library id', fakeAsync(() => {
findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse)); findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse));
spyOn(alfrescoApi.sitesApi, 'getSite').and.callFake(() => { spyOn(sitesService, 'getSite').and.callFake(() => {
return Promise.reject(); return throwError('error');
}); });
fixture.detectChanges(); fixture.detectChanges();
@@ -87,8 +91,8 @@ describe('LibraryDialogComponent', () => {
it('should not change custom library id on title input', fakeAsync(() => { it('should not change custom library id on title input', fakeAsync(() => {
findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse)); findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse));
spyOn(alfrescoApi.sitesApi, 'getSite').and.callFake(() => { spyOn(sitesService, 'getSite').and.callFake(() => {
return Promise.reject(); return throwError('error');
}); });
fixture.detectChanges(); fixture.detectChanges();
@@ -107,7 +111,7 @@ describe('LibraryDialogComponent', () => {
})); }));
it('should invalidate form when library id already exists', fakeAsync(() => { it('should invalidate form when library id already exists', fakeAsync(() => {
spyOn(alfrescoApi.sitesApi, 'getSite').and.returnValue(Promise.resolve()); spyOn(sitesService, 'getSite').and.returnValue(of(null));
fixture.detectChanges(); fixture.detectChanges();
component.form.controls.id.setValue('existingLibrary'); component.form.controls.id.setValue('existingLibrary');
@@ -123,11 +127,11 @@ describe('LibraryDialogComponent', () => {
it('should create site when form is valid', fakeAsync(() => { it('should create site when form is valid', fakeAsync(() => {
findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse)); findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse));
spyOn(alfrescoApi.sitesApi, 'createSite').and.returnValue( spyOn(sitesService, 'createSite').and.returnValue(
Promise.resolve() of({entry: {id: 'fake-id'}}).pipe(delay(100))
); );
spyOn(alfrescoApi.sitesApi, 'getSite').and.callFake(() => { spyOn(sitesService, 'getSite').and.callFake(() => {
return Promise.reject(); return throwError('error');
}); });
fixture.detectChanges(); fixture.detectChanges();
@@ -138,9 +142,18 @@ describe('LibraryDialogComponent', () => {
component.submit(); component.submit();
fixture.detectChanges(); fixture.detectChanges();
flush(); const confirmButton = fixture.nativeElement.querySelector(`[data-automation-id="create-library-id"]`);
expect(component.disableCreateButton).toBe(true);
expect(confirmButton.disabled).toBe(true);
expect(alfrescoApi.sitesApi.createSite).toHaveBeenCalledWith({ tick(500);
flushMicrotasks();
fixture.detectChanges();
expect(confirmButton.disabled).toBe(false);
expect(component.disableCreateButton).toBe(false);
expect(sitesService.createSite).toHaveBeenCalledWith({
id: 'library-title', id: 'library-title',
title: 'library title', title: 'library title',
description: '', description: '',
@@ -150,10 +163,10 @@ describe('LibraryDialogComponent', () => {
it('should not create site when form is invalid', fakeAsync(() => { it('should not create site when form is invalid', fakeAsync(() => {
findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse)); findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse));
spyOn(alfrescoApi.sitesApi, 'createSite').and.returnValue( spyOn(sitesService, 'createSite').and.returnValue(
Promise.resolve({}) Promise.resolve({})
); );
spyOn(alfrescoApi.sitesApi, 'getSite').and.returnValue(Promise.resolve()); spyOn(sitesService, 'getSite').and.returnValue(of(null));
fixture.detectChanges(); fixture.detectChanges();
component.form.controls.title.setValue('existingLibrary'); component.form.controls.title.setValue('existingLibrary');
@@ -165,11 +178,11 @@ describe('LibraryDialogComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
flush(); flush();
expect(alfrescoApi.sitesApi.createSite).not.toHaveBeenCalled(); expect(sitesService.createSite).not.toHaveBeenCalled();
})); }));
it('should notify when library title is already used', fakeAsync(() => { it('should notify when library title is already used', fakeAsync(() => {
spyOn(alfrescoApi.sitesApi, 'getSite').and.returnValue(Promise.resolve()); spyOn(sitesService, 'getSite').and.returnValue(of(null));
findSitesSpy.and.returnValue(Promise.resolve( findSitesSpy.and.returnValue(Promise.resolve(
{ list: { entries: [{ entry: { title: 'TEST', id: 'library-id' } }] } } { list: { entries: [{ entry: { title: 'TEST', id: 'library-id' } }] } }
)); ));
@@ -186,11 +199,11 @@ describe('LibraryDialogComponent', () => {
it('should notify on 409 conflict error (might be in trash)', fakeAsync(() => { it('should notify on 409 conflict error (might be in trash)', fakeAsync(() => {
findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse)); findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse));
const error = { message: '{ "error": { "statusCode": 409 } }' }; const error = { message: '{ "error": { "statusCode": 409 } }' };
spyOn(alfrescoApi.sitesApi, 'createSite').and.callFake(() => { spyOn(sitesService, 'createSite').and.callFake(() => {
return Promise.reject(error); return throwError(error);
}); });
spyOn(alfrescoApi.sitesApi, 'getSite').and.callFake(() => { spyOn(sitesService, 'getSite').and.callFake(() => {
return Promise.reject(); return throwError('error');
}); });
fixture.detectChanges(); fixture.detectChanges();
@@ -210,8 +223,8 @@ describe('LibraryDialogComponent', () => {
it('should not translate library title if value is not a valid id', fakeAsync(() => { it('should not translate library title if value is not a valid id', fakeAsync(() => {
findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse)); findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse));
spyOn(alfrescoApi.sitesApi, 'getSite').and.callFake(() => { spyOn(sitesService, 'getSite').and.callFake(() => {
return Promise.reject(); return throwError('error');
}); });
fixture.detectChanges(); fixture.detectChanges();
@@ -225,8 +238,8 @@ describe('LibraryDialogComponent', () => {
it('should translate library title partially for library id', fakeAsync(() => { it('should translate library title partially for library id', fakeAsync(() => {
findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse)); findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse));
spyOn(alfrescoApi.sitesApi, 'getSite').and.callFake(() => { spyOn(sitesService, 'getSite').and.callFake(() => {
return Promise.reject(); return throwError('error');
}); });
fixture.detectChanges(); fixture.detectChanges();
@@ -240,8 +253,8 @@ describe('LibraryDialogComponent', () => {
it('should translate library title multiple space character to one dash for library id', fakeAsync(() => { it('should translate library title multiple space character to one dash for library id', fakeAsync(() => {
findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse)); findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse));
spyOn(alfrescoApi.sitesApi, 'getSite').and.callFake(() => { spyOn(sitesService, 'getSite').and.callFake(() => {
return Promise.reject(); return throwError('error');
}); });
fixture.detectChanges(); fixture.detectChanges();
@@ -255,8 +268,8 @@ describe('LibraryDialogComponent', () => {
it('should invalidate library title if is too short', fakeAsync(() => { it('should invalidate library title if is too short', fakeAsync(() => {
findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse)); findSitesSpy.and.returnValue(Promise.resolve(findSitesResponse));
spyOn(alfrescoApi.sitesApi, 'getSite').and.callFake(() => { spyOn(sitesService, 'getSite').and.callFake(() => {
return Promise.reject(); return throwError('error');
}); });
fixture.detectChanges(); fixture.detectChanges();

View File

@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Observable, Subject, from } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { import {
Component, Component,
OnInit, OnInit,
@@ -33,8 +33,8 @@ import {
} from '@angular/forms'; } from '@angular/forms';
import { MatDialogRef } from '@angular/material/dialog'; import { MatDialogRef } from '@angular/material/dialog';
import { SiteBodyCreate, SiteEntry, SitePaging } from '@alfresco/js-api'; import { SiteBodyCreate, SiteEntry, SitePaging } from '@alfresco/js-api';
import { AlfrescoApiService } from '@alfresco/adf-core'; import { AlfrescoApiService, SitesService } from '@alfresco/adf-core';
import { debounceTime, mergeMap, takeUntil } from 'rxjs/operators'; import { debounceTime, finalize, mergeMap, takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-library-dialog', selector: 'adf-library-dialog',
@@ -70,9 +70,11 @@ export class LibraryDialogComponent implements OnInit, OnDestroy {
disabled: false disabled: false
} }
]; ];
disableCreateButton = false;
constructor( constructor(
private alfrescoApiService: AlfrescoApiService, private alfrescoApiService: AlfrescoApiService,
private sitesService: SitesService,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private dialog: MatDialogRef<LibraryDialogComponent> private dialog: MatDialogRef<LibraryDialogComponent>
) {} ) {}
@@ -152,7 +154,8 @@ export class LibraryDialogComponent implements OnInit, OnDestroy {
return; return;
} }
this.create().subscribe( this.disableCreateButton = true;
this.create().pipe(finalize(() => this.disableCreateButton = false)).subscribe(
(node: SiteEntry) => { (node: SiteEntry) => {
this.success.emit(node); this.success.emit(node);
dialog.close(node); dialog.close(node);
@@ -174,7 +177,7 @@ export class LibraryDialogComponent implements OnInit, OnDestroy {
visibility visibility
}; };
return from(this.alfrescoApiService.sitesApi.createSite(siteBody)); return this.sitesService.createSite(siteBody);
} }
private sanitize(input: string) { private sanitize(input: string) {
@@ -219,7 +222,7 @@ export class LibraryDialogComponent implements OnInit, OnDestroy {
} }
} }
private async findLibraryByTitle(libraryTitle: string): Promise<SitePaging> { private findLibraryByTitle(libraryTitle: string): Promise<SitePaging> {
return this.alfrescoApiService return this.alfrescoApiService
.getInstance() .getInstance()
.core.queriesApi.findSites(libraryTitle, { .core.queriesApi.findSites(libraryTitle, {
@@ -267,9 +270,7 @@ export class LibraryDialogComponent implements OnInit, OnDestroy {
return new Promise((resolve) => { return new Promise((resolve) => {
timer = setTimeout(() => { timer = setTimeout(() => {
return from( return this.sitesService.getSite(control.value).subscribe(
this.alfrescoApiService.sitesApi.getSite(control.value)
).subscribe(
() => resolve({ message: 'LIBRARY.ERRORS.EXISTENT_SITE' }), () => resolve({ message: 'LIBRARY.ERRORS.EXISTENT_SITE' }),
() => resolve(null) () => resolve(null)
); );

View File

@@ -20,7 +20,10 @@ import { from, Observable, throwError } from 'rxjs';
import { AlfrescoApiService } from './alfresco-api.service'; import { AlfrescoApiService } from './alfresco-api.service';
import { import {
MinimalNode, MinimalNode,
SiteEntry, SiteGroupEntry, SiteGroupPaging, SiteBodyCreate,
SiteEntry,
SiteGroupEntry,
SiteGroupPaging,
SiteMemberEntry, SiteMemberEntry,
SiteMemberPaging, SiteMemberPaging,
SiteMembershipBodyCreate, SiteMembershipBodyCreate,
@@ -42,6 +45,18 @@ export class SitesService {
this.sitesApi = new SitesApi(apiService.getInstance()); this.sitesApi = new SitesApi(apiService.getInstance());
} }
/**
* Create a site
* @param siteBody SiteBodyCreate to create site
* @returns site SiteEntry
*/
createSite(siteBody: SiteBodyCreate): Observable<SiteEntry> {
return from(this.sitesApi.createSite(siteBody))
.pipe(
catchError((err: any) => this.handleError(err))
);
}
/** /**
* Gets a list of all sites in the repository. * Gets a list of all sites in the repository.
* @param opts Options supported by JS-API * @param opts Options supported by JS-API