mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-07-24 17:31:52 +00:00
MNT-25070: ADW - Search request is altered when using quote marks (#4666)
* [MNT-25070] adjust helper functions to handle special characters in queries * [MNT-25070] fixes doubled requests on imperative navigation * [MNT-25070] introduces unit tests for added search utility features * [MNT-25070] clean-up * [MNT-25070] adjusts [XAT-5579] e2e * [MNT-25070] exclude failed e2e * [MNT-25070] readebility improvements; memory leaks handling * [MNT-25070] migrate from nested subscription to switchMap * [MNT-25070] adds unit tests for changes * [MNT-25070] removes any type from test setup * [MNT-25070] fixes same custom query reapply parsing issue
This commit is contained in:
@@ -3,5 +3,9 @@
|
|||||||
"XAT-5600": "https://hyland.atlassian.net/browse/ACS-6928",
|
"XAT-5600": "https://hyland.atlassian.net/browse/ACS-6928",
|
||||||
"XAT-17697": "https://hyland.atlassian.net/browse/ACS-7464",
|
"XAT-17697": "https://hyland.atlassian.net/browse/ACS-7464",
|
||||||
"XAT-17121": "https://hyland.atlassian.net/browse/ACS-9795",
|
"XAT-17121": "https://hyland.atlassian.net/browse/ACS-9795",
|
||||||
"XAT-17702": "https://hyland.atlassian.net/browse/ACS-9795"
|
"XAT-17702": "https://hyland.atlassian.net/browse/ACS-9795",
|
||||||
|
"XAT-17701": "https://hyland.atlassian.net/browse/ACS-9860",
|
||||||
|
"XAT-17700": "https://hyland.atlassian.net/browse/ACS-9860",
|
||||||
|
"XAT-5581": "https://hyland.atlassian.net/browse/ACS-9860",
|
||||||
|
"XAT-5589": "https://hyland.atlassian.net/browse/ACS-9860"
|
||||||
}
|
}
|
||||||
|
@@ -28,7 +28,7 @@ import { SearchQueryBuilderService } from '@alfresco/adf-content-services';
|
|||||||
import { AppConfigService, NotificationService } from '@alfresco/adf-core';
|
import { AppConfigService, NotificationService } from '@alfresco/adf-core';
|
||||||
import { Component, DestroyRef, inject, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
import { Component, DestroyRef, inject, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||||
import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu';
|
import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu';
|
||||||
import { ActivatedRoute, Params, PRIMARY_OUTLET, Router, UrlSegment, UrlSegmentGroup, UrlTree } from '@angular/router';
|
import { ActivatedRoute, NavigationSkipped, Params, PRIMARY_OUTLET, Router, UrlSegment, UrlSegmentGroup, UrlTree } from '@angular/router';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { SearchInputControlComponent } from '../search-input-control/search-input-control.component';
|
import { SearchInputControlComponent } from '../search-input-control/search-input-control.component';
|
||||||
import { SearchNavigationService } from '../search-navigation.service';
|
import { SearchNavigationService } from '../search-navigation.service';
|
||||||
@@ -44,6 +44,8 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
|
|||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { extractSearchedWordFromEncodedQuery } from '../../../utils/aca-search-utils';
|
import { extractSearchedWordFromEncodedQuery } from '../../../utils/aca-search-utils';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
|
import { merge } from 'rxjs/internal/observable/merge';
|
||||||
|
import { filter, map, withLatestFrom } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -119,13 +121,22 @@ export class SearchInputComponent implements OnInit, OnDestroy {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.showInputValue();
|
this.showInputValue();
|
||||||
|
|
||||||
this.route.queryParams.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((params: Params) => {
|
merge(
|
||||||
const encodedQuery = params['q'];
|
this.route.queryParams,
|
||||||
if (encodedQuery && this.searchInputControl) {
|
this.router.events.pipe(
|
||||||
this.searchedWord = extractSearchedWordFromEncodedQuery(encodedQuery);
|
filter((e) => e instanceof NavigationSkipped),
|
||||||
this.searchInputControl.searchTerm = this.searchedWord;
|
withLatestFrom(this.route.queryParams),
|
||||||
}
|
map(([, params]) => params)
|
||||||
});
|
)
|
||||||
|
)
|
||||||
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
|
.subscribe((params: Params) => {
|
||||||
|
const encodedQuery = params['q'];
|
||||||
|
if (encodedQuery && this.searchInputControl) {
|
||||||
|
this.searchedWord = extractSearchedWordFromEncodedQuery(encodedQuery);
|
||||||
|
this.searchInputControl.searchTerm = this.searchedWord;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.appHookService.library400Error.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
|
this.appHookService.library400Error.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
|
||||||
this.has400LibraryError = true;
|
this.has400LibraryError = true;
|
||||||
|
@@ -29,7 +29,7 @@ import { Store } from '@ngrx/store';
|
|||||||
import { NavigateToFolder } from '@alfresco/aca-shared/store';
|
import { NavigateToFolder } from '@alfresco/aca-shared/store';
|
||||||
import { Pagination, SearchRequest } from '@alfresco/js-api';
|
import { Pagination, SearchRequest } from '@alfresco/js-api';
|
||||||
import { SavedSearchesService, SearchQueryBuilderService } from '@alfresco/adf-content-services';
|
import { SavedSearchesService, SearchQueryBuilderService } from '@alfresco/adf-content-services';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Event, NavigationStart, Params, Router } from '@angular/router';
|
||||||
import { BehaviorSubject, of, Subject, throwError } from 'rxjs';
|
import { BehaviorSubject, of, Subject, throwError } from 'rxjs';
|
||||||
import { AppTestingModule } from '../../../testing/app-testing.module';
|
import { AppTestingModule } from '../../../testing/app-testing.module';
|
||||||
import { AppService } from '@alfresco/aca-shared';
|
import { AppService } from '@alfresco/aca-shared';
|
||||||
@@ -52,7 +52,9 @@ describe('SearchComponent', () => {
|
|||||||
let router: Router;
|
let router: Router;
|
||||||
let route: ActivatedRoute;
|
let route: ActivatedRoute;
|
||||||
const searchRequest = {} as SearchRequest;
|
const searchRequest = {} as SearchRequest;
|
||||||
let params: BehaviorSubject<any>;
|
let params: BehaviorSubject<Params>;
|
||||||
|
let queryParams: Subject<Params>;
|
||||||
|
let routerEvents: Subject<Event>;
|
||||||
let showErrorSpy: jasmine.Spy<(message: string, action?: string, interpolateArgs?: any, showAction?: boolean) => MatSnackBarRef<any>>;
|
let showErrorSpy: jasmine.Spy<(message: string, action?: string, interpolateArgs?: any, showAction?: boolean) => MatSnackBarRef<any>>;
|
||||||
let showInfoSpy: jasmine.Spy<(message: string, action?: string, interpolateArgs?: any, showAction?: boolean) => MatSnackBarRef<any>>;
|
let showInfoSpy: jasmine.Spy<(message: string, action?: string, interpolateArgs?: any, showAction?: boolean) => MatSnackBarRef<any>>;
|
||||||
let loader: HarnessLoader;
|
let loader: HarnessLoader;
|
||||||
@@ -66,6 +68,14 @@ describe('SearchComponent', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
params = new BehaviorSubject({ q: 'TYPE: "cm:folder" AND %28=cm: name: email OR cm: name: budget%29' });
|
params = new BehaviorSubject({ q: 'TYPE: "cm:folder" AND %28=cm: name: email OR cm: name: budget%29' });
|
||||||
|
queryParams = new Subject();
|
||||||
|
routerEvents = new Subject();
|
||||||
|
|
||||||
|
const routerMock = jasmine.createSpyObj<Router>('Router', ['navigate'], {
|
||||||
|
url: '/mock-search-url',
|
||||||
|
events: routerEvents
|
||||||
|
});
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [AppTestingModule, SearchResultsComponent, MatSnackBarModule, MatMenuModule, NoopAnimationsModule],
|
imports: [AppTestingModule, SearchResultsComponent, MatSnackBarModule, MatMenuModule, NoopAnimationsModule],
|
||||||
providers: [
|
providers: [
|
||||||
@@ -94,9 +104,11 @@ describe('SearchComponent', () => {
|
|||||||
sortingPreferenceKey: ''
|
sortingPreferenceKey: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
params: params.asObservable()
|
params: params.asObservable(),
|
||||||
|
queryParams: queryParams.asObservable()
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
{ provide: Router, useValue: routerMock }
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -106,7 +118,6 @@ describe('SearchComponent', () => {
|
|||||||
translate = TestBed.inject(TranslationService);
|
translate = TestBed.inject(TranslationService);
|
||||||
router = TestBed.inject(Router);
|
router = TestBed.inject(Router);
|
||||||
route = TestBed.inject(ActivatedRoute);
|
route = TestBed.inject(ActivatedRoute);
|
||||||
route.queryParams = of({});
|
|
||||||
|
|
||||||
const notificationService = TestBed.inject(NotificationService);
|
const notificationService = TestBed.inject(NotificationService);
|
||||||
showErrorSpy = spyOn(notificationService, 'showError');
|
showErrorSpy = spyOn(notificationService, 'showError');
|
||||||
@@ -305,5 +316,24 @@ describe('SearchComponent', () => {
|
|||||||
expect(showErrorSpy).toHaveBeenCalledWith('APP.BROWSE.SEARCH.SAVE_SEARCH.EDIT_DIALOG.ERROR_MESSAGE');
|
expect(showErrorSpy).toHaveBeenCalledWith('APP.BROWSE.SEARCH.SAVE_SEARCH.EDIT_DIALOG.ERROR_MESSAGE');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should call execute once on page reload', fakeAsync(() => {
|
||||||
|
spyOn(queryBuilder, 'execute');
|
||||||
|
queryParams.next({ q: encodeQuery({ userQuery: 'cm:name:"test*"' }) });
|
||||||
|
|
||||||
|
tick();
|
||||||
|
|
||||||
|
expect(queryBuilder.execute).toHaveBeenCalledTimes(1);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should NOT call execute on navigation to search page', fakeAsync(() => {
|
||||||
|
spyOn(queryBuilder, 'execute');
|
||||||
|
routerEvents.next(new NavigationStart(1, '/mock-search-url', 'imperative'));
|
||||||
|
queryParams.next({ q: encodeQuery({ userQuery: 'cm:name:"test*"' }) });
|
||||||
|
|
||||||
|
tick();
|
||||||
|
|
||||||
|
expect(queryBuilder.execute).not.toHaveBeenCalled();
|
||||||
|
}));
|
||||||
|
|
||||||
testHeader(SearchResultsComponent, false);
|
testHeader(SearchResultsComponent, false);
|
||||||
});
|
});
|
||||||
|
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
import { ChangeDetectorRef, Component, inject, OnInit, ViewEncapsulation } from '@angular/core';
|
import { ChangeDetectorRef, Component, inject, OnInit, ViewEncapsulation } from '@angular/core';
|
||||||
import { NodeEntry, Pagination, ResultSetPaging } from '@alfresco/js-api';
|
import { NodeEntry, Pagination, ResultSetPaging } from '@alfresco/js-api';
|
||||||
import { ActivatedRoute, Params } from '@angular/router';
|
import { ActivatedRoute, NavigationStart } from '@angular/router';
|
||||||
import {
|
import {
|
||||||
AlfrescoViewerComponent,
|
AlfrescoViewerComponent,
|
||||||
DocumentListComponent,
|
DocumentListComponent,
|
||||||
@@ -64,7 +64,7 @@ import {
|
|||||||
ToolbarComponent
|
ToolbarComponent
|
||||||
} from '@alfresco/aca-shared';
|
} from '@alfresco/aca-shared';
|
||||||
import { SearchSortingDefinition } from '@alfresco/adf-content-services/lib/search/models/search-sorting-definition.interface';
|
import { SearchSortingDefinition } from '@alfresco/adf-content-services/lib/search/models/search-sorting-definition.interface';
|
||||||
import { take, takeUntil } from 'rxjs/operators';
|
import { filter, first, map, startWith, switchMap, take, tap, toArray } from 'rxjs/operators';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { TranslatePipe } from '@ngx-translate/core';
|
import { TranslatePipe } from '@ngx-translate/core';
|
||||||
import { SearchInputComponent } from '../search-input/search-input.component';
|
import { SearchInputComponent } from '../search-input/search-input.component';
|
||||||
@@ -85,7 +85,7 @@ import {
|
|||||||
formatSearchTerm
|
formatSearchTerm
|
||||||
} from '../../../utils/aca-search-utils';
|
} from '../../../utils/aca-search-utils';
|
||||||
import { SaveSearchDirective } from '../search-save/directive/save-search.directive';
|
import { SaveSearchDirective } from '../search-save/directive/save-search.directive';
|
||||||
import { Subject } from 'rxjs';
|
import { combineLatest, of } from 'rxjs';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
|
||||||
@@ -145,7 +145,6 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
|
|||||||
encodedQuery: string;
|
encodedQuery: string;
|
||||||
searchConfig: SearchConfiguration;
|
searchConfig: SearchConfiguration;
|
||||||
|
|
||||||
private readonly loadedFilters$ = new Subject<void>();
|
|
||||||
constructor(
|
constructor(
|
||||||
tagsService: TagService,
|
tagsService: TagService,
|
||||||
private readonly queryBuilder: SearchQueryBuilderService,
|
private readonly queryBuilder: SearchQueryBuilderService,
|
||||||
@@ -163,13 +162,10 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
|
|||||||
maxItems: 25
|
maxItems: 25
|
||||||
};
|
};
|
||||||
|
|
||||||
this.queryBuilder.configUpdated
|
this.queryBuilder.configUpdated.pipe(takeUntilDestroyed()).subscribe((searchConfig) => {
|
||||||
.asObservable()
|
this.searchConfig = searchConfig;
|
||||||
.pipe(takeUntilDestroyed())
|
this.updateUserQuery();
|
||||||
.subscribe((searchConfig) => {
|
});
|
||||||
this.searchConfig = searchConfig;
|
|
||||||
this.updateUserQuery();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -207,42 +203,55 @@ 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.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((params: Params) => {
|
this.route.queryParams
|
||||||
this.savedSearchesService
|
.pipe(
|
||||||
.getSavedSearches()
|
takeUntilDestroyed(this.destroyRef),
|
||||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
switchMap((params) =>
|
||||||
.subscribe((savedSearches) => {
|
this.savedSearchesService.getSavedSearches().pipe(
|
||||||
const savedSearchFound = savedSearches.find((savedSearch) => savedSearch.encodedUrl === encodeURIComponent(params[this.queryParamName]));
|
first(),
|
||||||
this.initialSavedSearch = savedSearchFound !== undefined ? savedSearchFound : this.initialSavedSearch;
|
map((savedSearches) => savedSearches.find((savedSearch) => savedSearch.encodedUrl === encodeURIComponent(params[this.queryParamName])))
|
||||||
});
|
)
|
||||||
if (params[this.queryParamName]) {
|
)
|
||||||
this.isLoading = true;
|
)
|
||||||
}
|
.subscribe((savedSearches) => {
|
||||||
this.loadedFilters$.next();
|
this.initialSavedSearch = savedSearches;
|
||||||
this.encodedQuery = params[this.queryParamName] || null;
|
});
|
||||||
this.searchedWord = extractSearchedWordFromEncodedQuery(this.encodedQuery);
|
|
||||||
this.updateUserQuery();
|
combineLatest([
|
||||||
const filtersFromEncodedQuery = extractFiltersFromEncodedQuery(this.encodedQuery);
|
this.route.queryParams,
|
||||||
if (filtersFromEncodedQuery !== null) {
|
this.router.events.pipe(
|
||||||
const filtersToLoad = this.queryBuilder.categories.length;
|
filter((e): e is NavigationStart => e instanceof NavigationStart),
|
||||||
let loadedFilters = this.searchedWord === '' ? 0 : 1;
|
startWith(null)
|
||||||
this.queryBuilder.filterLoaded
|
)
|
||||||
.asObservable()
|
])
|
||||||
.pipe(takeUntilDestroyed(this.destroyRef), takeUntil(this.loadedFilters$))
|
.pipe(
|
||||||
.subscribe(() => {
|
takeUntilDestroyed(this.destroyRef),
|
||||||
loadedFilters++;
|
tap(([params]) => {
|
||||||
if (filtersToLoad === loadedFilters) {
|
this.encodedQuery = params[this.queryParamName];
|
||||||
this.loadedFilters$.next();
|
this.isLoading = !!this.encodedQuery;
|
||||||
this.queryBuilder.execute(false);
|
|
||||||
}
|
this.searchedWord = extractSearchedWordFromEncodedQuery(this.encodedQuery);
|
||||||
});
|
this.updateUserQuery();
|
||||||
this.queryBuilder.populateFilters.next(filtersFromEncodedQuery);
|
|
||||||
} else {
|
const filtersFromEncodedQuery = extractFiltersFromEncodedQuery(this.encodedQuery);
|
||||||
this.queryBuilder.populateFilters.next({});
|
this.queryBuilder.populateFilters.next(filtersFromEncodedQuery || {});
|
||||||
this.queryBuilder.execute(false);
|
}),
|
||||||
}
|
switchMap(([, navigationStartEvent]) => {
|
||||||
this.queryBuilder.userQuery = extractUserQueryFromEncodedQuery(this.encodedQuery);
|
const filtersToLoad = this.queryBuilder.categories.length;
|
||||||
});
|
|
||||||
|
const filtersAreLoaded = filtersToLoad ? this.queryBuilder.filterLoaded.pipe(take(filtersToLoad), toArray()) : of(null);
|
||||||
|
|
||||||
|
return filtersAreLoaded.pipe(map(() => navigationStartEvent));
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe((navigationStartEvent) => {
|
||||||
|
const shouldExecuteQuery = this.shouldExecuteQuery(navigationStartEvent, this.encodedQuery);
|
||||||
|
this.queryBuilder.userQuery = extractUserQueryFromEncodedQuery(this.encodedQuery);
|
||||||
|
|
||||||
|
if (shouldExecuteQuery) {
|
||||||
|
this.queryBuilder.execute(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,4 +347,14 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
|
|||||||
const updatedUserQuery = formatSearchTerm(this.searchedWord, this.searchConfig['app:fields']);
|
const updatedUserQuery = formatSearchTerm(this.searchedWord, this.searchConfig['app:fields']);
|
||||||
this.queryBuilder.userQuery = updatedUserQuery;
|
this.queryBuilder.userQuery = updatedUserQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private shouldExecuteQuery(navigationStartEvent: NavigationStart | null, query: string | undefined): boolean {
|
||||||
|
if (!navigationStartEvent || navigationStartEvent.navigationTrigger === 'popstate' || navigationStartEvent.navigationTrigger === 'hashchange') {
|
||||||
|
return true;
|
||||||
|
} else if (navigationStartEvent.navigationTrigger === 'imperative') {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return !!query;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -125,6 +125,11 @@ describe('SearchUtils', () => {
|
|||||||
const query = { userQuery: 'cm:name:"test"' };
|
const query = { userQuery: 'cm:name:"test"' };
|
||||||
expect(extractUserQueryFromEncodedQuery(encodeQuery(query))).toBe('cm:name:"test"');
|
expect(extractUserQueryFromEncodedQuery(encodeQuery(query))).toBe('cm:name:"test"');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should properly trim set of parentheses from extracted user query', () => {
|
||||||
|
const query = { userQuery: '(cm:name:"test")' };
|
||||||
|
expect(extractUserQueryFromEncodedQuery(encodeQuery(query))).toBe('cm:name:"test"');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('extractSearchedWordFromEncodedQuery', () => {
|
describe('extractSearchedWordFromEncodedQuery', () => {
|
||||||
@@ -139,6 +144,11 @@ describe('SearchUtils', () => {
|
|||||||
const query = { userQuery: 'cm:name:"test*"' };
|
const query = { userQuery: 'cm:name:"test*"' };
|
||||||
expect(extractSearchedWordFromEncodedQuery(encodeQuery(query))).toBe('test');
|
expect(extractSearchedWordFromEncodedQuery(encodeQuery(query))).toBe('test');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should properly extract search term for custom search', () => {
|
||||||
|
const query = { userQuery: '"test"' };
|
||||||
|
expect(extractSearchedWordFromEncodedQuery(encodeQuery(query))).toBe('test');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('extractFiltersFromEncodedQuery', () => {
|
describe('extractFiltersFromEncodedQuery', () => {
|
||||||
|
@@ -99,7 +99,7 @@ export function formatSearchTerm(userInput: string, fields = ['cm:name']): strin
|
|||||||
export function extractUserQueryFromEncodedQuery(encodedQuery: string): string {
|
export function extractUserQueryFromEncodedQuery(encodedQuery: string): string {
|
||||||
if (encodedQuery) {
|
if (encodedQuery) {
|
||||||
const decodedQuery: { [key: string]: any } = JSON.parse(new TextDecoder().decode(Uint8Array.from(atob(encodedQuery), (c) => c.charCodeAt(0))));
|
const decodedQuery: { [key: string]: any } = JSON.parse(new TextDecoder().decode(Uint8Array.from(atob(encodedQuery), (c) => c.charCodeAt(0))));
|
||||||
return decodedQuery.userQuery;
|
return trimUserQuery(decodedQuery.userQuery);
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ export function extractSearchedWordFromEncodedQuery(encodedQuery: string): strin
|
|||||||
.split('AND')
|
.split('AND')
|
||||||
.map((searchCondition) => {
|
.map((searchCondition) => {
|
||||||
const searchTerm = searchCondition.split('"')[1];
|
const searchTerm = searchCondition.split('"')[1];
|
||||||
return searchTerm === '*' ? searchTerm : searchTerm.slice(0, -1);
|
return searchTerm?.endsWith('*') && searchTerm !== '*' ? searchTerm.slice(0, -1) : searchTerm;
|
||||||
})
|
})
|
||||||
.join(' ')
|
.join(' ')
|
||||||
: '';
|
: '';
|
||||||
@@ -139,3 +139,14 @@ export function extractFiltersFromEncodedQuery(encodedQuery: string): any {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trims one set of parentheses from parsed user query.
|
||||||
|
*
|
||||||
|
* @param userQuery user query parsed from encoded query
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
|
function trimUserQuery(userQuery: string): string {
|
||||||
|
const trimmedQuery = userQuery?.replace(/^\(/, '');
|
||||||
|
return trimmedQuery?.replace(/\)$/, '') ?? '';
|
||||||
|
}
|
||||||
|
@@ -90,7 +90,9 @@ export class SearchFiltersProperties extends BaseComponent {
|
|||||||
|
|
||||||
if (fileTypeInputText) {
|
if (fileTypeInputText) {
|
||||||
await this.fileTypeInput?.fill(fileTypeInputText);
|
await this.fileTypeInput?.fill(fileTypeInputText);
|
||||||
await this.dropdownOptions.first().click();
|
const targetDropdownOption = this.page.locator(`mat-option`, { hasText: fileTypeInputText });
|
||||||
|
|
||||||
|
await targetDropdownOption.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
await page.searchFilters.menuCardApply.click();
|
await page.searchFilters.menuCardApply.click();
|
||||||
|
Reference in New Issue
Block a user