mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2026-04-23 22:30:24 +00:00
[ACS-10730] The ‘Save Changes’ button becomes disabled after modifying the search or filter. (#4929)
This commit is contained in:
committed by
GitHub
parent
9cd6c9154b
commit
7df4e84729
@@ -60,6 +60,7 @@
|
||||
mat-button
|
||||
acaSaveSearch
|
||||
[acaSaveSearchQuery]="encodedQuery"
|
||||
(searchSaved)="onSaveSearch()"
|
||||
[disabled]="!encodedQuery"
|
||||
class="aca-content__save-search-action"
|
||||
title="{{ 'APP.BROWSE.SEARCH.SAVE_SEARCH.ACTION_BUTTON' | translate }}"
|
||||
|
||||
@@ -266,6 +266,17 @@ describe('SearchComponent', () => {
|
||||
expect(component.initialSavedSearch).toEqual({ name: 'test', encodedUrl: encodeQuery({ name: 'test' }), order: 0 });
|
||||
});
|
||||
|
||||
it('should get initial saved search after creating a new one', () => {
|
||||
route.queryParams = of({ q: encodeQuery({ name: 'test' }) });
|
||||
component.onSaveSearch();
|
||||
expect(component.initialSavedSearch).toEqual({ name: 'test', encodedUrl: encodeQuery({ name: 'test' }), order: 0 });
|
||||
});
|
||||
|
||||
it('should clear context save search in service on component destroy', () => {
|
||||
component.ngOnDestroy();
|
||||
expect(TestBed.inject(SavedSearchesContextService).currentContextSavedSearch).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should render a menu with 2 options when initial saved search is found', async () => {
|
||||
route.queryParams = of({ q: encodeQuery({ name: 'test' }) });
|
||||
component.ngOnInit();
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ChangeDetectorRef, Component, inject, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ChangeDetectorRef, Component, inject, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { NodeEntry, Pagination, ResultSetPaging } from '@alfresco/js-api';
|
||||
import { ActivatedRoute, NavigationStart } from '@angular/router';
|
||||
import {
|
||||
@@ -131,7 +131,7 @@ import { SavedSearchesContextService } from '../../../services/saved-searches-co
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
styleUrls: ['./search-results.component.scss']
|
||||
})
|
||||
export class SearchResultsComponent extends PageComponent implements OnInit {
|
||||
export class SearchResultsComponent extends PageComponent implements OnInit, OnDestroy {
|
||||
private notificationService = inject(NotificationService);
|
||||
|
||||
infoDrawerPreview$ = this.store.select(infoDrawerPreview);
|
||||
@@ -214,19 +214,9 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
|
||||
this.columns = this.extensions.documentListPresets.searchResults || [];
|
||||
|
||||
if (this.route) {
|
||||
this.route.queryParams
|
||||
.pipe(
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
switchMap((params) =>
|
||||
this.savedSearchesService.savedSearches$.pipe(
|
||||
first(),
|
||||
map((savedSearches) => savedSearches.find((savedSearch) => savedSearch.encodedUrl === encodeURIComponent(params[this.queryParamName])))
|
||||
)
|
||||
)
|
||||
)
|
||||
.subscribe((savedSearches) => {
|
||||
this.initialSavedSearch = savedSearches;
|
||||
});
|
||||
this.selectInitialSavedSearch().subscribe((savedSearches) => {
|
||||
this.initialSavedSearch = savedSearches;
|
||||
});
|
||||
|
||||
combineLatest([
|
||||
this.route.queryParams,
|
||||
@@ -269,6 +259,10 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.savedSearchesService.currentContextSavedSearch = undefined;
|
||||
}
|
||||
|
||||
onSearchError(error: { message: any }) {
|
||||
let message: string;
|
||||
try {
|
||||
@@ -362,6 +356,15 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
onSaveSearch(): void {
|
||||
this.selectInitialSavedSearch()
|
||||
.pipe(take(1))
|
||||
.subscribe((savedSearch) => {
|
||||
this.initialSavedSearch = savedSearch;
|
||||
this.savedSearchesService.currentContextSavedSearch = savedSearch;
|
||||
});
|
||||
}
|
||||
|
||||
private shouldExecuteQuery(navigationStartEvent: NavigationStart | null, query: string | undefined): boolean {
|
||||
const hasQueryChanged = query !== this.previousEncodedQuery;
|
||||
this.previousEncodedQuery = query;
|
||||
@@ -374,4 +377,20 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
|
||||
return !!query;
|
||||
}
|
||||
}
|
||||
|
||||
private selectInitialSavedSearch(): Observable<SavedSearch> {
|
||||
return this.route.queryParams.pipe(
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
switchMap((params) =>
|
||||
this.savedSearchesService.savedSearches$.pipe(
|
||||
first(),
|
||||
map(
|
||||
(savedSearches) =>
|
||||
savedSearches.find((savedSearch) => savedSearch.encodedUrl === encodeURIComponent(params[this.queryParamName])) ||
|
||||
this.savedSearchesService.currentContextSavedSearch
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,12 +74,12 @@ describe('SaveSearchDialogComponent', () => {
|
||||
expect(savedSearchesService.saveSearch).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should save search, show snackbar message and close modal if form is valid', fakeAsync(() => {
|
||||
it('should save search, show snackbar message and close modal with emitting true value if form is valid', fakeAsync(() => {
|
||||
spyOn(savedSearchesService, 'saveSearch').and.callThrough();
|
||||
spyOn(notificationService, 'showInfo');
|
||||
setFormValuesAndSubmit();
|
||||
expect(notificationService.showInfo).toHaveBeenCalledWith('APP.BROWSE.SEARCH.SAVE_SEARCH.SAVE_SUCCESS');
|
||||
expect(dialogRef.close).toHaveBeenCalled();
|
||||
expect(dialogRef.close).toHaveBeenCalledWith(true);
|
||||
}));
|
||||
|
||||
it('should show snackbar error if there is save error', fakeAsync(() => {
|
||||
|
||||
@@ -96,7 +96,7 @@ export class SaveSearchDialogComponent {
|
||||
.pipe(take(1))
|
||||
.subscribe({
|
||||
next: () => {
|
||||
this.dialog.close();
|
||||
this.dialog.close(true);
|
||||
this.notificationService.showInfo('APP.BROWSE.SEARCH.SAVE_SEARCH.SAVE_SUCCESS');
|
||||
this.disableSubmitButton = false;
|
||||
},
|
||||
|
||||
@@ -24,19 +24,24 @@
|
||||
|
||||
import { Component, DebugElement } from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { of } from 'rxjs';
|
||||
import { of, Subject } from 'rxjs';
|
||||
import { SaveSearchDirective } from './save-search.directive';
|
||||
import { SaveSearchDialogComponent } from '../dialog/save-search-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-test-component',
|
||||
template: '<div acaSaveSearch="searchQuery" acaSaveSearchQuery="encodedQuery"></div>',
|
||||
template: '<div acaSaveSearch="searchQuery" (searchSaved)="onSaveSearchSuccess($event)" acaSaveSearchQuery="encodedQuery"></div>',
|
||||
imports: [SaveSearchDirective]
|
||||
})
|
||||
class TestComponent {
|
||||
searchQuery = 'encodedQuery';
|
||||
isSavedWithSuccess = false;
|
||||
|
||||
onSaveSearchSuccess(value: boolean): void {
|
||||
this.isSavedWithSuccess = value;
|
||||
}
|
||||
}
|
||||
|
||||
describe('SaveSearchDirective', () => {
|
||||
@@ -57,7 +62,7 @@ describe('SaveSearchDirective', () => {
|
||||
provide: MatDialog,
|
||||
useValue: {
|
||||
open: () => ({
|
||||
afterClosed: jasmine.createSpy('afterClosed').and.returnValue(of(null))
|
||||
afterClosed: jasmine.createSpy('afterClosed').and.returnValue(of(true))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -86,4 +91,20 @@ describe('SaveSearchDirective', () => {
|
||||
|
||||
expect(dialog.open).toHaveBeenCalledWith(SaveSearchDialogComponent, expectedConfig);
|
||||
});
|
||||
|
||||
it('should emit event on save search success', () => {
|
||||
const afterClosed$ = new Subject<boolean>();
|
||||
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => afterClosed$.asObservable()
|
||||
} as MatDialogRef<SaveSearchDialogComponent>);
|
||||
|
||||
element.triggerEventHandler('click', event);
|
||||
|
||||
afterClosed$.next(true);
|
||||
afterClosed$.complete();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.componentInstance.isSavedWithSuccess).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,9 +22,10 @@
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
|
||||
import { DestroyRef, Directive, ElementRef, EventEmitter, HostListener, inject, Input, Output } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { SaveSearchDialogComponent } from '../dialog/save-search-dialog.component';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
|
||||
interface SaveSearchDirectiveDialogData {
|
||||
searchUrl: string;
|
||||
@@ -39,10 +40,13 @@ export class SaveSearchDirective {
|
||||
@Input()
|
||||
acaSaveSearchQuery: string;
|
||||
|
||||
constructor(
|
||||
private readonly dialogRef: MatDialog,
|
||||
private readonly elementRef: ElementRef<HTMLElement>
|
||||
) {}
|
||||
/** Outputs a true value when search was successfully saved */
|
||||
@Output()
|
||||
searchSaved = new EventEmitter<boolean>();
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private readonly dialogRef = inject(MatDialog);
|
||||
private readonly elementRef = inject(ElementRef<HTMLElement>);
|
||||
|
||||
@HostListener('click', ['$event'])
|
||||
onClick(event: MouseEvent) {
|
||||
@@ -52,7 +56,15 @@ export class SaveSearchDirective {
|
||||
}
|
||||
|
||||
private openDialog(): void {
|
||||
this.dialogRef.open(SaveSearchDialogComponent, { ...this.getDialogConfig(), restoreFocus: true });
|
||||
const dialog = this.dialogRef.open(SaveSearchDialogComponent, { ...this.getDialogConfig(), restoreFocus: true });
|
||||
dialog
|
||||
.afterClosed()
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((value: boolean) => {
|
||||
if (value) {
|
||||
this.searchSaved.emit(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private getDialogConfig(): { data: SaveSearchDirectiveDialogData } {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
@if (item) {
|
||||
<app-expand-menu [item]="item" />
|
||||
<app-expand-menu [item]="item" (actionClicked)="onActionClicked($event)" />
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import { AppTestingModule } from '../../../../testing/app-testing.module';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { SavedSearchesContextService } from '../../../../services/saved-searches-context.service';
|
||||
import { SavedSearch } from '@alfresco/adf-content-services';
|
||||
import { NavBarLinkRef } from '@alfresco/adf-extensions';
|
||||
|
||||
describe('SaveSearchSidenavComponent', () => {
|
||||
let fixture: ComponentFixture<SaveSearchSidenavComponent>;
|
||||
@@ -36,8 +37,8 @@ describe('SaveSearchSidenavComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
const mockService: Partial<SavedSearchesContextService> = {
|
||||
currentContextSavedSearch: undefined,
|
||||
init: (): void => {},
|
||||
|
||||
get savedSearches$(): Observable<SavedSearch[]> {
|
||||
return of([]);
|
||||
}
|
||||
@@ -94,4 +95,46 @@ describe('SaveSearchSidenavComponent', () => {
|
||||
id: 'search1'
|
||||
});
|
||||
}));
|
||||
|
||||
describe('onActionClicked', () => {
|
||||
beforeEach(() => {
|
||||
spyOnProperty(savedSearchesService, 'savedSearches$', 'get').and.returnValue(of([{ name: 'abc', order: 0, encodedUrl: 'abc' }]));
|
||||
component.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should set currentContextSavedSearch when matching saved search is found', () => {
|
||||
const selectedLinkRef: NavBarLinkRef = {
|
||||
id: 'search-test',
|
||||
icon: '',
|
||||
title: 'abc',
|
||||
description: 'test',
|
||||
route: 'search?q=encoded',
|
||||
url: 'search?q=encoded'
|
||||
};
|
||||
|
||||
component.onActionClicked(selectedLinkRef);
|
||||
|
||||
expect(component.savedSearchesService.currentContextSavedSearch).toEqual({
|
||||
name: 'abc',
|
||||
encodedUrl: 'abc',
|
||||
order: 0
|
||||
});
|
||||
});
|
||||
|
||||
it('should set currentContextSavedSearch to undefined when no matching saved search is found', () => {
|
||||
const selectedLinkRef: NavBarLinkRef = {
|
||||
id: 'search-unknown',
|
||||
icon: '',
|
||||
title: 'Unknown Search',
|
||||
description: 'Unknown Search',
|
||||
route: 'search?q=unknown',
|
||||
url: 'search?q=unknown'
|
||||
};
|
||||
|
||||
component.onActionClicked(selectedLinkRef);
|
||||
|
||||
expect(component.savedSearchesService.currentContextSavedSearch).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -42,17 +42,19 @@ export class SaveSearchSidenavComponent implements OnInit {
|
||||
translationService = inject(TranslationService);
|
||||
item: NavBarLinkRef;
|
||||
|
||||
private savedSearchCount = 0;
|
||||
private savedSearches: SavedSearch[];
|
||||
|
||||
private readonly manageSearchesId = 'manage-saved-searches';
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private readonly userPreferenceService = inject(UserPreferencesService);
|
||||
|
||||
private savedSearchCount = 0;
|
||||
|
||||
ngOnInit() {
|
||||
this.savedSearchesService.init();
|
||||
this.savedSearchesService.savedSearches$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((savedSearches) => {
|
||||
this.item = this.createNavBarLinkRef(savedSearches);
|
||||
this.savedSearchCount = savedSearches.length;
|
||||
this.savedSearches = savedSearches;
|
||||
});
|
||||
this.userPreferenceService
|
||||
.select(UserPreferenceValues.Locale)
|
||||
@@ -64,6 +66,11 @@ export class SaveSearchSidenavComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
onActionClicked(selectedLinkRef: NavBarLinkRef): void {
|
||||
const selectedSavedSearch = this.savedSearches?.find((savedSearch) => savedSearch.name === selectedLinkRef.title);
|
||||
this.savedSearchesService.currentContextSavedSearch = selectedSavedSearch;
|
||||
}
|
||||
|
||||
private createNavBarLinkRef(children: SavedSearch[]): NavBarLinkRef {
|
||||
const mappedChildren = children
|
||||
.map((child) => ({
|
||||
|
||||
@@ -23,11 +23,12 @@
|
||||
*/
|
||||
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { Subject } from 'rxjs';
|
||||
import { of, Subject } from 'rxjs';
|
||||
|
||||
import { SavedSearchesContextService } from './saved-searches-context.service';
|
||||
import { SavedSearch, SavedSearchesLegacyService, SavedSearchesService } from '@alfresco/adf-content-services';
|
||||
import { IsFeatureSupportedInCurrentAcsPipe } from '../pipes/is-feature-supported.pipe';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
|
||||
describe('SavedSearchesContextService', () => {
|
||||
let legacySpy: jasmine.SpyObj<SavedSearchesLegacyService>;
|
||||
@@ -38,7 +39,6 @@ describe('SavedSearchesContextService', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
legacySpy = jasmine.createSpyObj('SavedSearchesLegacyService', [
|
||||
'savedSearches$',
|
||||
'init',
|
||||
'getSavedSearches',
|
||||
'saveSearch',
|
||||
@@ -46,9 +46,12 @@ describe('SavedSearchesContextService', () => {
|
||||
'deleteSavedSearch',
|
||||
'changeOrder'
|
||||
]);
|
||||
legacySpy.getSavedSearches.and.returnValue(of([]));
|
||||
legacySpy.saveSearch.and.returnValue(of({} as NodeEntry));
|
||||
legacySpy.editSavedSearch.and.returnValue(of({} as NodeEntry));
|
||||
legacySpy.deleteSavedSearch.and.returnValue(of({} as NodeEntry));
|
||||
|
||||
modernSpy = jasmine.createSpyObj('SavedSearchesService', [
|
||||
'savedSearches$',
|
||||
'init',
|
||||
'getSavedSearches',
|
||||
'saveSearch',
|
||||
@@ -56,6 +59,10 @@ describe('SavedSearchesContextService', () => {
|
||||
'deleteSavedSearch',
|
||||
'changeOrder'
|
||||
]);
|
||||
modernSpy.getSavedSearches.and.returnValue(of([]));
|
||||
modernSpy.saveSearch.and.returnValue(of({} as NodeEntry));
|
||||
modernSpy.editSavedSearch.and.returnValue(of({} as NodeEntry));
|
||||
modernSpy.deleteSavedSearch.and.returnValue(of({} as NodeEntry));
|
||||
|
||||
isSupported = new Subject<boolean>();
|
||||
|
||||
@@ -79,53 +86,70 @@ describe('SavedSearchesContextService', () => {
|
||||
isSupported.next(true);
|
||||
});
|
||||
|
||||
it('should use modern service when feature is supported', () => {
|
||||
it('should use modern service when feature is supported', (done) => {
|
||||
service.init();
|
||||
expect(legacySpy.init).not.toHaveBeenCalled();
|
||||
expect(modernSpy.init).toHaveBeenCalled();
|
||||
setTimeout(() => {
|
||||
expect(legacySpy.init).not.toHaveBeenCalled();
|
||||
expect(modernSpy.init).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should delegate init() call to a current strategy', () => {
|
||||
it('should delegate init() call to a current strategy', (done) => {
|
||||
service.init();
|
||||
expect(modernSpy.init).toHaveBeenCalled();
|
||||
setTimeout(() => {
|
||||
expect(modernSpy.init).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should delegate getSavedSearches() call to a current strategy', () => {
|
||||
service.getSavedSearches();
|
||||
expect(modernSpy.getSavedSearches).toHaveBeenCalled();
|
||||
it('should delegate getSavedSearches() call to a current strategy', (done) => {
|
||||
service.getSavedSearches().subscribe(() => {
|
||||
expect(modernSpy.getSavedSearches).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should delegate saveSearch() call to a current strategy', () => {
|
||||
it('should delegate saveSearch() call to a current strategy', (done) => {
|
||||
const newSavedSearch = { name: 'Test Search', description: 'Test Description', encodedUrl: 'http://example.com' };
|
||||
service.saveSearch(newSavedSearch);
|
||||
expect(modernSpy.saveSearch).toHaveBeenCalledWith(newSavedSearch);
|
||||
service.saveSearch(newSavedSearch).subscribe(() => {
|
||||
expect(modernSpy.saveSearch).toHaveBeenCalledWith(newSavedSearch);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should delegate editSavedSearch() call to a current strategy', () => {
|
||||
it('should delegate editSavedSearch() call to a current strategy', (done) => {
|
||||
const updatedSavedSearch = {
|
||||
name: 'Updated Search',
|
||||
description: 'Updated Description',
|
||||
encodedUrl: 'http://example.com',
|
||||
order: 1
|
||||
};
|
||||
service.editSavedSearch(updatedSavedSearch);
|
||||
expect(modernSpy.editSavedSearch).toHaveBeenCalledWith(updatedSavedSearch);
|
||||
service.editSavedSearch(updatedSavedSearch).subscribe(() => {
|
||||
expect(modernSpy.editSavedSearch).toHaveBeenCalledWith(updatedSavedSearch);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should delegate deleteSavedSearch() call to a current strategy', () => {
|
||||
it('should delegate deleteSavedSearch() call to a current strategy', (done) => {
|
||||
const deletedSavedSearch = {
|
||||
name: 'Deleted Search',
|
||||
description: 'Deleted Description',
|
||||
encodedUrl: 'http://example.com',
|
||||
order: 2
|
||||
};
|
||||
service.deleteSavedSearch(deletedSavedSearch);
|
||||
expect(modernSpy.deleteSavedSearch).toHaveBeenCalledWith(deletedSavedSearch);
|
||||
service.deleteSavedSearch(deletedSavedSearch).subscribe(() => {
|
||||
expect(modernSpy.deleteSavedSearch).toHaveBeenCalledWith(deletedSavedSearch);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should delegate changeOrder() call to a current strategy', () => {
|
||||
it('should delegate changeOrder() call to a current strategy', (done) => {
|
||||
service.changeOrder(0, 1);
|
||||
expect(modernSpy.changeOrder).toHaveBeenCalledWith(0, 1);
|
||||
setTimeout(() => {
|
||||
expect(modernSpy.changeOrder).toHaveBeenCalledWith(0, 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -134,53 +158,70 @@ describe('SavedSearchesContextService', () => {
|
||||
isSupported.next(false);
|
||||
});
|
||||
|
||||
it('should use legacy service when feature is NOT supported', () => {
|
||||
it('should use legacy service when feature is NOT supported', (done) => {
|
||||
service.init();
|
||||
expect(legacySpy.init).toHaveBeenCalled();
|
||||
expect(modernSpy.init).not.toHaveBeenCalled();
|
||||
setTimeout(() => {
|
||||
expect(legacySpy.init).toHaveBeenCalled();
|
||||
expect(modernSpy.init).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should delegate init() call to a current strategy', () => {
|
||||
it('should delegate init() call to a current strategy', (done) => {
|
||||
service.init();
|
||||
expect(legacySpy.init).toHaveBeenCalled();
|
||||
setTimeout(() => {
|
||||
expect(legacySpy.init).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should delegate getSavedSearches() call to a current strategy', () => {
|
||||
service.getSavedSearches();
|
||||
expect(legacySpy.getSavedSearches).toHaveBeenCalled();
|
||||
it('should delegate getSavedSearches() call to a current strategy', (done) => {
|
||||
service.getSavedSearches().subscribe(() => {
|
||||
expect(legacySpy.getSavedSearches).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should delegate saveSearch() call to a current strategy', () => {
|
||||
it('should delegate saveSearch() call to a current strategy', (done) => {
|
||||
const newSavedSearch = { name: 'Test Search', description: 'Test Description', encodedUrl: 'http://example.com' } as SavedSearch;
|
||||
service.saveSearch(newSavedSearch);
|
||||
expect(legacySpy.saveSearch).toHaveBeenCalledWith(newSavedSearch);
|
||||
service.saveSearch(newSavedSearch).subscribe(() => {
|
||||
expect(legacySpy.saveSearch).toHaveBeenCalledWith(newSavedSearch);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should delegate editSavedSearch() call to a current strategy', () => {
|
||||
it('should delegate editSavedSearch() call to a current strategy', (done) => {
|
||||
const updatedSavedSearch: SavedSearch = {
|
||||
name: 'Updated Search',
|
||||
description: 'Updated Description',
|
||||
encodedUrl: 'http://example.com',
|
||||
order: 1
|
||||
};
|
||||
service.editSavedSearch(updatedSavedSearch);
|
||||
expect(legacySpy.editSavedSearch).toHaveBeenCalledWith(updatedSavedSearch);
|
||||
service.editSavedSearch(updatedSavedSearch).subscribe(() => {
|
||||
expect(legacySpy.editSavedSearch).toHaveBeenCalledWith(updatedSavedSearch);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should delegate deleteSavedSearch() call to a current strategy', () => {
|
||||
it('should delegate deleteSavedSearch() call to a current strategy', (done) => {
|
||||
const deletedSavedSearch: SavedSearch = {
|
||||
name: 'Deleted Search',
|
||||
description: 'Deleted Description',
|
||||
encodedUrl: 'http://example.com',
|
||||
order: 2
|
||||
};
|
||||
service.deleteSavedSearch(deletedSavedSearch);
|
||||
expect(legacySpy.deleteSavedSearch).toHaveBeenCalledWith(deletedSavedSearch);
|
||||
service.deleteSavedSearch(deletedSavedSearch).subscribe(() => {
|
||||
expect(legacySpy.deleteSavedSearch).toHaveBeenCalledWith(deletedSavedSearch);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should delegate changeOrder() call to a current strategy', () => {
|
||||
it('should delegate changeOrder() call to a current strategy', (done) => {
|
||||
service.changeOrder(0, 1);
|
||||
expect(legacySpy.changeOrder).toHaveBeenCalledWith(0, 1);
|
||||
setTimeout(() => {
|
||||
expect(legacySpy.changeOrder).toHaveBeenCalledWith(0, 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,8 +33,9 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SavedSearchesContextService implements SavedSearchStrategy {
|
||||
currentContextSavedSearch: SavedSearch;
|
||||
|
||||
private readonly strategy$ = new ReplaySubject<SavedSearchStrategy>(1);
|
||||
private strategy: SavedSearchStrategy;
|
||||
|
||||
constructor(
|
||||
private readonly legacyService: SavedSearchesLegacyService,
|
||||
@@ -45,8 +46,8 @@ export class SavedSearchesContextService implements SavedSearchStrategy {
|
||||
.transform('isPreferencesApiAvailable')
|
||||
.pipe(takeUntilDestroyed())
|
||||
.subscribe((isSupported) => {
|
||||
this.strategy = isSupported ? this.modernService : this.legacyService;
|
||||
this.strategy$.next(this.strategy);
|
||||
const strategy = isSupported ? this.modernService : this.legacyService;
|
||||
this.strategy$.next(strategy);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -55,26 +56,34 @@ export class SavedSearchesContextService implements SavedSearchStrategy {
|
||||
}
|
||||
|
||||
init(): void {
|
||||
this.strategy$.pipe(take(1)).subscribe((strategy) => strategy.init());
|
||||
this.executeOnStrategyVoid((strategy) => strategy.init());
|
||||
}
|
||||
|
||||
getSavedSearches(): Observable<SavedSearch[]> {
|
||||
return this.strategy.getSavedSearches();
|
||||
return this.executeOnStrategy((strategy) => strategy.getSavedSearches());
|
||||
}
|
||||
|
||||
saveSearch(newSaveSearch: Pick<SavedSearch, 'name' | 'description' | 'encodedUrl'>): Observable<NodeEntry> {
|
||||
return this.strategy.saveSearch(newSaveSearch);
|
||||
return this.executeOnStrategy((strategy) => strategy.saveSearch(newSaveSearch));
|
||||
}
|
||||
|
||||
editSavedSearch(updatedSavedSearch: SavedSearch): Observable<NodeEntry> {
|
||||
return this.strategy.editSavedSearch(updatedSavedSearch);
|
||||
return this.executeOnStrategy((strategy) => strategy.editSavedSearch(updatedSavedSearch));
|
||||
}
|
||||
|
||||
deleteSavedSearch(deletedSavedSearch: SavedSearch): Observable<NodeEntry> {
|
||||
return this.strategy.deleteSavedSearch(deletedSavedSearch);
|
||||
return this.executeOnStrategy((strategy) => strategy.deleteSavedSearch(deletedSavedSearch));
|
||||
}
|
||||
|
||||
changeOrder(previousIndex: number, currentIndex: number): void {
|
||||
this.strategy.changeOrder(previousIndex, currentIndex);
|
||||
this.executeOnStrategyVoid((strategy) => strategy.changeOrder(previousIndex, currentIndex));
|
||||
}
|
||||
|
||||
private executeOnStrategy<T>(action: (strategy: SavedSearchStrategy) => Observable<T>): Observable<T> {
|
||||
return this.strategy$.pipe(take(1), switchMap(action));
|
||||
}
|
||||
|
||||
private executeOnStrategyVoid(action: (strategy: SavedSearchStrategy) => void): void {
|
||||
this.strategy$.pipe(take(1)).subscribe(action);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user