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