mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
[ACA-19] show search libraries hint (#802)
* [ACA-19] show hint on 400 error * [ACA-19] unit test * [ACA-19] small change * [ACA-19] unit test * [ACA-19] unit tests * [ACA-19] avoid memory leaks with takeUntil * [ACA-19] remove comment & formatting * [ACA-19] update documentation
This commit is contained in:
parent
ff0891009e
commit
dcacbc1210
@ -307,6 +307,7 @@ The content actions are applied to the toolbars for the following Views:
|
||||
- Favorites
|
||||
- Trash
|
||||
- Search Results
|
||||
- Libraries Search Results
|
||||
|
||||
## Context Menu
|
||||
|
||||
|
@ -17,6 +17,7 @@ The components are used to create custom:
|
||||
| app.toolbar.toggleInfoDrawer | ToggleInfoDrawerComponent | The toolbar button component that toggles Info Drawer for the selection. |
|
||||
| app.toolbar.toggleFavorite | ToggleFavoriteComponent | The toolbar button component that toggles Favorite state for the selection. |
|
||||
| app.toolbar.toggleFavoriteLibrary | ToggleFavoriteLibraryComponent | The toolbar button component that toggles Favorite library state for the selection. |
|
||||
| app.toolbar.toggleJoinLibrary | ToggleJoinLibraryComponent | The toolbar button component that toggles Join/Cancel Join request for the selected library. |
|
||||
|
||||
See [Registration](/extending/registration) section for more details
|
||||
on how to register your own entries to be re-used at runtime.
|
||||
|
@ -143,6 +143,9 @@ The button will be visible only when the linked rule evaluates to `true`.
|
||||
| app.selection.file | A single File node is selected. |
|
||||
| app.selection.file.canShare | User is able to share the selected file. |
|
||||
| app.selection.library | A single Library node is selected. |
|
||||
| app.selection.isPrivateLibrary | A private Library node is selected. |
|
||||
| app.selection.hasLibraryRole | The selected Library node has a role property. |
|
||||
| app.selection.hasNoLibraryRole | The selected Library node has no role property. |
|
||||
| app.selection.folder | A single Folder node is selected. |
|
||||
| app.selection.folder.canUpdate | User has permissions to update the selected folder. |
|
||||
| repository.isQuickShareEnabled | Whether the quick share repository option is enabled or not. |
|
||||
@ -163,18 +166,18 @@ You can also negate any rule by utilizing a `!` prefix:
|
||||
| --------------------------------- | ------------------------------------------------------- |
|
||||
| app.navigation.folder.canCreate | User can create content in the currently opened folder. |
|
||||
| app.navigation.folder.canUpload | User can upload content to the currently opened folder. |
|
||||
| app.navigation.isTrashcan | User is using the **Trashcan** page. |
|
||||
| app.navigation.isTrashcan | User is using the **Trashcan** page. |
|
||||
| app.navigation.isNotTrashcan | Current page is not a **Trashcan**. |
|
||||
| app.navigation.isLibraries | User is using the **Libraries** page. |
|
||||
| app.navigation.isNotLibraries | Current page is not **Libraries**. |
|
||||
| app.navigation.isSharedFiles | User is using the **Shared Files** page. |
|
||||
| app.navigation.isLibraries | User is using a **Libraries** page. |
|
||||
| app.navigation.isNotLibraries | Current page is not a **Libraries** page. |
|
||||
| app.navigation.isSharedFiles | User is using the **Shared Files** page. |
|
||||
| app.navigation.isNotSharedFiles | Current page is not **Shared Files**. |
|
||||
| app.navigation.isFavorites | User is using the **Favorites** page. |
|
||||
| app.navigation.isFavorites | User is using the **Favorites** page. |
|
||||
| app.navigation.isNotFavorites | Current page is not **Favorites** |
|
||||
| app.navigation.isRecentFiles | User is using the **Recent Files** page. |
|
||||
| app.navigation.isRecentFiles | User is using the **Recent Files** page. |
|
||||
| app.navigation.isNotRecentFiles | Current page is not **Recent Files**. |
|
||||
| app.navigation.isSearchResults | User is using the **Search Results** page. |
|
||||
| app.navigation.isNotSearchResults | Current page is not the **Search Results**. |
|
||||
| app.navigation.isSearchResults | User is using the **Search Results** page. |
|
||||
| app.navigation.isNotSearchResults | Current page is not the **Search Results**. |
|
||||
|
||||
<p class="tip">
|
||||
See [Registration](/extending/registration) section for more details
|
||||
@ -187,7 +190,7 @@ The rule in the example below evaluates to `true` if all the conditions are met:
|
||||
|
||||
- user has selected node(s)
|
||||
- user is not using the **Trashcan** page
|
||||
- user is not using the **Libraries** page
|
||||
- user is not using a **Libraries** page (**My Libraries**, **Favorite Libraries** or **Libraries Search Results** pages)
|
||||
|
||||
```json
|
||||
{
|
||||
|
@ -24,9 +24,73 @@
|
||||
*/
|
||||
|
||||
import { SearchInputControlComponent } from './search-input-control.component';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { AppTestingModule } from '../../../testing/app-testing.module';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
|
||||
describe('SearchInputControlComponent', () => {
|
||||
it('should be defined', () => {
|
||||
expect(SearchInputControlComponent).toBeDefined();
|
||||
let fixture: ComponentFixture<SearchInputControlComponent>;
|
||||
let component: SearchInputControlComponent;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AppTestingModule],
|
||||
declarations: [SearchInputControlComponent],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
})
|
||||
.compileComponents()
|
||||
.then(() => {
|
||||
fixture = TestBed.createComponent(SearchInputControlComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should emit submit event on searchSubmit', async () => {
|
||||
const keyboardEvent = { target: { value: 'a' } };
|
||||
|
||||
let eventArgs = null;
|
||||
component.submit.subscribe(args => (eventArgs = args));
|
||||
|
||||
await component.searchSubmit(keyboardEvent);
|
||||
expect(eventArgs).toBe(keyboardEvent);
|
||||
});
|
||||
|
||||
it('should emit searchChange event on inputChange', async () => {
|
||||
const searchTerm = 'b';
|
||||
|
||||
let eventArgs = null;
|
||||
component.searchChange.subscribe(args => (eventArgs = args));
|
||||
|
||||
await component.inputChange(searchTerm);
|
||||
expect(eventArgs).toBe(searchTerm);
|
||||
});
|
||||
|
||||
it('should emit searchChange event on clear', async () => {
|
||||
let eventArgs = null;
|
||||
component.searchChange.subscribe(args => (eventArgs = args));
|
||||
|
||||
await component.clear();
|
||||
expect(eventArgs).toBe('');
|
||||
});
|
||||
|
||||
it('should clear searchTerm', async () => {
|
||||
component.searchTerm = 'c';
|
||||
fixture.detectChanges();
|
||||
|
||||
await component.clear();
|
||||
expect(component.searchTerm).toBe('');
|
||||
});
|
||||
|
||||
it('should check if searchTerm has a length less than 2', () => {
|
||||
expect(component.isTermTooShort()).toBe(false);
|
||||
|
||||
component.searchTerm = 'd';
|
||||
fixture.detectChanges();
|
||||
expect(component.isTermTooShort()).toBe(true);
|
||||
|
||||
component.searchTerm = 'dd';
|
||||
fixture.detectChanges();
|
||||
expect(component.isTermTooShort()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@ -87,8 +87,6 @@ export class SearchInputControlComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
isTermTooShort() {
|
||||
const alphanumericTerm = this.searchTerm.replace(/[^0-9a-z]/gi, '');
|
||||
|
||||
return this.searchTerm.length && alphanumericTerm.length < 2;
|
||||
return !!(this.searchTerm && this.searchTerm.length < 2);
|
||||
}
|
||||
}
|
||||
|
@ -39,11 +39,13 @@ import { SEARCH_BY_TERM, SearchByTermAction } from '../../../store/actions';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { SearchQueryBuilderService } from '@alfresco/adf-content-services';
|
||||
import { SearchLibrariesQueryBuilderService } from '../search-libraries-results/search-libraries-query-builder.service';
|
||||
import { ContentManagementService } from '../../../services/content-management.service';
|
||||
|
||||
describe('SearchInputComponent', () => {
|
||||
let fixture: ComponentFixture<SearchInputComponent>;
|
||||
let component: SearchInputComponent;
|
||||
let actions$: Actions;
|
||||
let content: ContentManagementService;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@ -56,11 +58,33 @@ describe('SearchInputComponent', () => {
|
||||
.then(() => {
|
||||
actions$ = TestBed.get(Actions);
|
||||
fixture = TestBed.createComponent(SearchInputComponent);
|
||||
content = TestBed.get(ContentManagementService);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should change flag on library400Error event', () => {
|
||||
expect(component.has400LibraryError).toBe(false);
|
||||
content.library400Error.next();
|
||||
|
||||
expect(component.has400LibraryError).toBe(true);
|
||||
});
|
||||
|
||||
it('should have no library constraint by default', () => {
|
||||
expect(component.hasLibraryConstraint()).toBe(false);
|
||||
});
|
||||
|
||||
it('should have library constraint on 400 error received', () => {
|
||||
const libItem = component.searchOptions.find(
|
||||
item => item.key.toLowerCase().indexOf('libraries') > 0
|
||||
);
|
||||
libItem.value = true;
|
||||
content.library400Error.next();
|
||||
|
||||
expect(component.hasLibraryConstraint()).toBe(true);
|
||||
});
|
||||
|
||||
describe('onSearchSubmit()', () => {
|
||||
it('should call search action with correct search options', fakeAsync(done => {
|
||||
const searchedTerm = 's';
|
||||
|
@ -23,7 +23,13 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
ViewEncapsulation
|
||||
} from '@angular/core';
|
||||
import {
|
||||
NavigationEnd,
|
||||
PRIMARY_OUTLET,
|
||||
@ -37,9 +43,11 @@ import { SearchInputControlComponent } from '../search-input-control/search-inpu
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppStore } from '../../../store/states/app.state';
|
||||
import { SearchByTermAction } from '../../../store/actions';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { filter, takeUntil } from 'rxjs/operators';
|
||||
import { SearchLibrariesQueryBuilderService } from '../search-libraries-results/search-libraries-query-builder.service';
|
||||
import { SearchQueryBuilderService } from '@alfresco/adf-content-services';
|
||||
import { ContentManagementService } from '../../../services/content-management.service';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
export enum SearchOptionIds {
|
||||
Files = 'files',
|
||||
@ -53,10 +61,12 @@ export enum SearchOptionIds {
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'aca-search-input' }
|
||||
})
|
||||
export class SearchInputComponent implements OnInit {
|
||||
export class SearchInputComponent implements OnInit, OnDestroy {
|
||||
onDestroy$: Subject<boolean> = new Subject<boolean>();
|
||||
hasOneChange = false;
|
||||
hasNewChange = false;
|
||||
navigationTimer: any;
|
||||
has400LibraryError = false;
|
||||
|
||||
searchedWord = null;
|
||||
searchOptions: Array<any> = [
|
||||
@ -86,6 +96,7 @@ export class SearchInputComponent implements OnInit {
|
||||
constructor(
|
||||
private librariesQueryBuilder: SearchLibrariesQueryBuilderService,
|
||||
private queryBuilder: SearchQueryBuilderService,
|
||||
private content: ContentManagementService,
|
||||
private router: Router,
|
||||
private store: Store<AppStore>
|
||||
) {}
|
||||
@ -94,15 +105,23 @@ export class SearchInputComponent implements OnInit {
|
||||
this.showInputValue();
|
||||
|
||||
this.router.events
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.pipe(filter(e => e instanceof RouterEvent))
|
||||
.subscribe(event => {
|
||||
if (event instanceof NavigationEnd) {
|
||||
this.showInputValue();
|
||||
}
|
||||
});
|
||||
|
||||
this.content.library400Error
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(() => {
|
||||
this.has400LibraryError = true;
|
||||
});
|
||||
}
|
||||
|
||||
showInputValue() {
|
||||
this.has400LibraryError = false;
|
||||
this.searchedWord = '';
|
||||
|
||||
if (this.onSearchResults || this.onLibrariesSearchResults) {
|
||||
@ -121,12 +140,18 @@ export class SearchInputComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.onDestroy$.next(true);
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the user submits the search, e.g. hits enter or clicks submit
|
||||
*
|
||||
* @param event Parameters relating to the search
|
||||
*/
|
||||
onSearchSubmit(event: KeyboardEvent) {
|
||||
this.has400LibraryError = false;
|
||||
const searchTerm = (event.target as HTMLInputElement).value;
|
||||
if (searchTerm) {
|
||||
this.store.dispatch(
|
||||
@ -136,6 +161,7 @@ export class SearchInputComponent implements OnInit {
|
||||
}
|
||||
|
||||
onSearchChange(searchTerm: string) {
|
||||
this.has400LibraryError = false;
|
||||
if (this.hasOneChange) {
|
||||
this.hasNewChange = true;
|
||||
} else {
|
||||
@ -158,6 +184,7 @@ export class SearchInputComponent implements OnInit {
|
||||
}
|
||||
|
||||
onOptionChange() {
|
||||
this.has400LibraryError = false;
|
||||
if (this.searchedWord) {
|
||||
if (this.isLibrariesChecked()) {
|
||||
if (this.onLibrariesSearchResults) {
|
||||
@ -213,7 +240,9 @@ export class SearchInputComponent implements OnInit {
|
||||
|
||||
hasLibraryConstraint(): boolean {
|
||||
if (this.isLibrariesChecked()) {
|
||||
return this.searchInputControl.isTermTooShort();
|
||||
return (
|
||||
this.has400LibraryError || this.searchInputControl.isTermTooShort()
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -93,4 +93,18 @@ describe('SearchLibrariesQueryBuilderService', () => {
|
||||
const compiled = builder.buildQuery();
|
||||
expect(compiled.opts).toEqual({ maxItems: 5, skipCount: 5 });
|
||||
});
|
||||
|
||||
it('should raise an event on error', async () => {
|
||||
const err = '{"error": {"statusCode": 400}}';
|
||||
spyOn(queriesApi, 'findSites').and.returnValue(Promise.reject(err));
|
||||
|
||||
const query = {};
|
||||
spyOn(builder, 'buildQuery').and.returnValue(query);
|
||||
|
||||
let eventArgs = null;
|
||||
builder.hadError.subscribe(args => (eventArgs = args));
|
||||
|
||||
await builder.execute();
|
||||
expect(eventArgs).toBe(err);
|
||||
});
|
||||
});
|
||||
|
@ -36,6 +36,7 @@ export class SearchLibrariesQueryBuilderService {
|
||||
|
||||
updated: Subject<any> = new Subject();
|
||||
executed: Subject<any> = new Subject();
|
||||
hadError: Subject<any> = new Subject();
|
||||
|
||||
paging: { maxItems?: number; skipCount?: number } = null;
|
||||
|
||||
@ -77,10 +78,13 @@ export class SearchLibrariesQueryBuilderService {
|
||||
return null;
|
||||
}
|
||||
|
||||
private findLibraries(libraryQuery: { term; opts }): Promise<SitePaging> {
|
||||
private findLibraries(libraryQuery): Promise<SitePaging> {
|
||||
return this.alfrescoApiService
|
||||
.getInstance()
|
||||
.core.queriesApi.findSites(libraryQuery.term, libraryQuery.opts)
|
||||
.catch(() => ({ list: { pagination: { totalItems: 0 }, entries: [] } }));
|
||||
.catch(err => {
|
||||
this.hadError.next(err);
|
||||
return { list: { pagination: { totalItems: 0 }, entries: [] } };
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,17 @@ export class SearchLibrariesResultsComponent extends PageComponent
|
||||
this.isLoading = false;
|
||||
}),
|
||||
|
||||
this.librariesQueryBuilder.hadError.subscribe(err => {
|
||||
try {
|
||||
const {
|
||||
error: { statusCode }
|
||||
} = JSON.parse(err.message);
|
||||
if (statusCode === 400) {
|
||||
this.content.library400Error.next();
|
||||
}
|
||||
} catch (e) {}
|
||||
}),
|
||||
|
||||
this.breakpointObserver
|
||||
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
|
||||
.subscribe(result => {
|
||||
|
169
src/app/directives/library-membership.directive.spec.ts
Normal file
169
src/app/directives/library-membership.directive.spec.ts
Normal file
@ -0,0 +1,169 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
import {
|
||||
AlfrescoApiService,
|
||||
AlfrescoApiServiceMock,
|
||||
AppConfigService,
|
||||
CoreModule,
|
||||
StorageService
|
||||
} from '@alfresco/adf-core';
|
||||
import { AppTestingModule } from '../testing/app-testing.module';
|
||||
import { DirectivesModule } from './directives.module';
|
||||
import { LibraryMembershipDirective } from './library-membership.directive';
|
||||
import { NO_ERRORS_SCHEMA, SimpleChange } from '@angular/core';
|
||||
|
||||
describe('LibraryMembershipDirective', () => {
|
||||
let alfrescoApiService: AlfrescoApiService;
|
||||
let directive: LibraryMembershipDirective;
|
||||
let peopleApi;
|
||||
let addMembershipSpy;
|
||||
let getMembershipSpy;
|
||||
let deleteMembershipSpy;
|
||||
|
||||
const testSiteEntry = {
|
||||
id: 'id-1',
|
||||
guid: 'site-1',
|
||||
title: 'aa t m',
|
||||
visibility: 'MODERATED'
|
||||
};
|
||||
const requestedMembershipResponse = {
|
||||
id: testSiteEntry.id,
|
||||
createdAt: '2018-11-14',
|
||||
site: testSiteEntry
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AppTestingModule, DirectivesModule, CoreModule.forRoot()],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
});
|
||||
alfrescoApiService = new AlfrescoApiServiceMock(
|
||||
new AppConfigService(null),
|
||||
new StorageService()
|
||||
);
|
||||
peopleApi = alfrescoApiService.getInstance().core.peopleApi;
|
||||
directive = new LibraryMembershipDirective(alfrescoApiService);
|
||||
});
|
||||
|
||||
describe('markMembershipRequest', () => {
|
||||
beforeEach(() => {
|
||||
getMembershipSpy = spyOn(
|
||||
peopleApi,
|
||||
'getSiteMembershipRequest'
|
||||
).and.returnValue(
|
||||
Promise.resolve({ entry: requestedMembershipResponse })
|
||||
);
|
||||
});
|
||||
|
||||
it('should not check membership requests if no entry is selected', fakeAsync(() => {
|
||||
const selection = {};
|
||||
const change = new SimpleChange(null, selection, true);
|
||||
directive.ngOnChanges({ selection: change });
|
||||
tick();
|
||||
expect(getMembershipSpy).not.toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should check if a membership request exists for the selected library', fakeAsync(() => {
|
||||
const selection = { entry: {} };
|
||||
const change = new SimpleChange(null, selection, true);
|
||||
directive.ngOnChanges({ selection: change });
|
||||
tick();
|
||||
expect(getMembershipSpy.calls.count()).toBe(1);
|
||||
}));
|
||||
|
||||
it('should remember when a membership request exists for selected library', fakeAsync(() => {
|
||||
const selection = { entry: testSiteEntry };
|
||||
const change = new SimpleChange(null, selection, true);
|
||||
directive.ngOnChanges({ selection: change });
|
||||
tick();
|
||||
expect(directive.targetSite.joinRequested).toBe(true);
|
||||
}));
|
||||
|
||||
it('should remember when a membership request is not found for selected library', fakeAsync(() => {
|
||||
getMembershipSpy.and.returnValue(Promise.reject());
|
||||
|
||||
const selection = { entry: testSiteEntry };
|
||||
const change = new SimpleChange(null, selection, true);
|
||||
directive.ngOnChanges({ selection: change });
|
||||
tick();
|
||||
expect(directive.targetSite.joinRequested).toBe(false);
|
||||
}));
|
||||
});
|
||||
|
||||
describe('toggleMembershipRequest', () => {
|
||||
beforeEach(() => {
|
||||
getMembershipSpy = spyOn(
|
||||
peopleApi,
|
||||
'getSiteMembershipRequest'
|
||||
).and.returnValue(
|
||||
Promise.resolve({ entry: requestedMembershipResponse })
|
||||
);
|
||||
addMembershipSpy = spyOn(
|
||||
peopleApi,
|
||||
'addSiteMembershipRequest'
|
||||
).and.returnValue(
|
||||
Promise.resolve({ entry: requestedMembershipResponse })
|
||||
);
|
||||
deleteMembershipSpy = spyOn(
|
||||
peopleApi,
|
||||
'removeSiteMembershipRequest'
|
||||
).and.returnValue(Promise.resolve({}));
|
||||
});
|
||||
|
||||
it('should do nothing if there is no selected library ', fakeAsync(() => {
|
||||
const selection = {};
|
||||
const change = new SimpleChange(null, selection, true);
|
||||
directive.ngOnChanges({ selection: change });
|
||||
tick();
|
||||
directive.toggleMembershipRequest();
|
||||
tick();
|
||||
expect(addMembershipSpy).not.toHaveBeenCalled();
|
||||
expect(deleteMembershipSpy).not.toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should delete membership request if there is one', fakeAsync(() => {
|
||||
const selection = { entry: testSiteEntry };
|
||||
const change = new SimpleChange(null, selection, true);
|
||||
directive.ngOnChanges({ selection: change });
|
||||
tick();
|
||||
directive.toggleMembershipRequest();
|
||||
tick();
|
||||
expect(deleteMembershipSpy).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should call API to make a membership request if there is none', fakeAsync(() => {
|
||||
const selection = { entry: { id: 'no-membership-requested' } };
|
||||
const change = new SimpleChange(null, selection, true);
|
||||
directive.ngOnChanges({ selection: change });
|
||||
tick();
|
||||
directive.toggleMembershipRequest();
|
||||
tick();
|
||||
expect(addMembershipSpy).toHaveBeenCalled();
|
||||
expect(deleteMembershipSpy).not.toHaveBeenCalled();
|
||||
}));
|
||||
});
|
||||
});
|
@ -90,11 +90,11 @@ export class LibraryMembershipDirective implements OnChanges {
|
||||
this.toggle.emit(info);
|
||||
},
|
||||
error => {
|
||||
const errWitMessage = {
|
||||
const errWithMessage = {
|
||||
error,
|
||||
i18nKey: 'APP.MESSAGES.ERRORS.JOIN_CANCEL_FAILED'
|
||||
};
|
||||
this.error.emit(errWitMessage);
|
||||
this.error.emit(errWithMessage);
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -124,11 +124,11 @@ export class LibraryMembershipDirective implements OnChanges {
|
||||
}
|
||||
},
|
||||
error => {
|
||||
const errWitMessage = {
|
||||
const errWithMessage = {
|
||||
error,
|
||||
i18nKey: 'APP.MESSAGES.ERRORS.JOIN_REQUEST_FAILED'
|
||||
};
|
||||
this.error.emit(errWitMessage);
|
||||
this.error.emit(errWithMessage);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -83,6 +83,7 @@ export class ContentManagementService {
|
||||
libraryCreated = new Subject<SiteEntry>();
|
||||
libraryUpdated = new Subject<SiteEntry>();
|
||||
libraryJoined = new Subject<string>();
|
||||
library400Error = new Subject<any>();
|
||||
joinLibraryToggle = new Subject<string>();
|
||||
linksUnshared = new Subject<any>();
|
||||
favoriteAdded = new Subject<Array<MinimalNodeEntity>>();
|
||||
|
Loading…
x
Reference in New Issue
Block a user