working callbacks, working search filtering/facets

This commit is contained in:
Jason Kulatunga 2023-05-10 19:34:57 -07:00
parent 4758f2adcc
commit 363dc49636
3 changed files with 134 additions and 43 deletions

View File

@ -7,6 +7,20 @@
.PHONY: test
test: backend-test frontend-test
.PHONY: serve-frontend
serve-web:
cd frontend
yarn dist -- -c sandbox
.PHONY: serve-frontend-prod
serve-web:
cd frontend
yarn dist -- -c prod
.PHONY: serve-backend
serve-web:
go run backend/cmd/fasten/fasten.go start --config ./config.dev.yaml --debug
########################################################################################################################
# Backend

View File

@ -7,15 +7,16 @@ import {MetadataSource} from '../../models/fasten/metadata-source';
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {ActivatedRoute} from '@angular/router';
import {environment} from '../../../environments/environment';
import {BehaviorSubject, forkJoin, Observable, Subject} from 'rxjs';
import {BehaviorSubject, forkJoin, Observable, of, Subject} from 'rxjs';
import {
LighthouseSourceSearch,
LighthouseSourceSearchAggregation,
LighthouseSourceSearchResult
} from '../../models/lighthouse/lighthouse-source-search';
import {debounceTime, distinctUntilChanged} from 'rxjs/operators';
import {debounceTime, distinctUntilChanged, pairwise, startWith} from 'rxjs/operators';
import {MedicalSourcesFilter, MedicalSourcesFilterService} from '../../services/medical-sources-filter.service';
import {FormControl, FormGroup} from '@angular/forms';
import * as _ from 'lodash';
// If you dont import this angular will import the wrong "Location"
export const sourceConnectWindowTimeout = 24*5000 //wait 2 minutes (5 * 24 = 120)
@ -78,7 +79,22 @@ export class MedicalSourcesComponent implements OnInit {
private activatedRoute: ActivatedRoute,
private filterService: MedicalSourcesFilterService,
private modalService: NgbModal,
) { }
) {
this.filterService.filterChanges.subscribe((filterInfo) => {
console.log("medical-sources - filterChanges", filterInfo)
//this function should only trigger when there's a change to the filter values -- which requires a new query
this.availableSourceList = []
this.resultLimits.totalItems = 0
this.resultLimits.scrollComplete = false
//update the form with data from route (don't emit a new patch event), then submit query
this.querySources(filterInfo?.filter).subscribe(null, null, () => {
console.log("querySources() complete")
})
})
}
ngOnInit(): void {
@ -92,7 +108,6 @@ export class MedicalSourcesComponent implements OnInit {
if(inProgressAvailableIndex > -1){
let sourcesInProgress = this.availableSourceList.splice(inProgressAvailableIndex, 1);
}
}
//we're not in a callback redirect, lets load the sources
if(this.activatedRoute.snapshot.queryParams['query']){
@ -100,26 +115,6 @@ export class MedicalSourcesComponent implements OnInit {
}
//changing the route should trigger a query
this.activatedRoute.queryParams
.subscribe(params => {
console.log("QUERY PARAMS CHANGED ON ROUTE", params); // {order: "popular"}
var updatedForm = this.filterService.parseQueryParams(params);
//this is a "breaking change" to the filter values, causing a reset and a new query
this.availableSourceList = []
this.resultLimits.totalItems = 0
this.resultLimits.scrollComplete = false
this.filterService.resetControl("categories")
// this.filterService.filterForm.setControl("categories", this.{: {}}, { emitEvent: false})
//update the form with data from route (don't emit a new patch event), then submit query
var searchObservable = this.querySources(this.filterService.toMedicalSourcesFilter(updatedForm));
searchObservable.subscribe(null, null, () => {
this.filterForm.patchValue(updatedForm, { emitEvent: false});
})
});
//register a callback for when the search box content changes
this.searchTermUpdate
.pipe(
@ -137,8 +132,10 @@ export class MedicalSourcesComponent implements OnInit {
}
private querySources(filter?: MedicalSourcesFilter): Observable<LighthouseSourceSearch> {
console.log("querySources()", filter)
if(this.loading){
return
console.log("already loading, ignoring querySources()")
return of(null)
}
//TODO: pass filter to function.
// this.location.replaceState('/dashboard','', this.filter)
@ -161,11 +158,12 @@ export class MedicalSourcesComponent implements OnInit {
return {metadata: result._source}
}))
//change the current Page (but don't cause a new query)
if(!wrapper?.hits || !wrapper?.hits || wrapper?.hits?.hits?.length == 0){
//check if scroll is complete.
if(!wrapper?.hits || !wrapper?.hits?.hits || wrapper?.hits?.hits?.length == 0 || wrapper?.hits?.total?.value == wrapper?.hits?.hits?.length){
console.log("SCROLL_COMPLETE!@@@@@@@@")
this.resultLimits.scrollComplete = true;
} else {
//change the current Page (but don't cause a new query)
console.log("SETTING NEXT SORT KEY:", wrapper.hits.hits[wrapper.hits.hits.length - 1].sort.join(','))
this.filterService.filterForm.patchValue({searchAfter: wrapper.hits.hits[wrapper.hits.hits.length - 1].sort.join(",")}, {emitEvent: false})
}
@ -218,7 +216,9 @@ export class MedicalSourcesComponent implements OnInit {
public onScroll(): void {
this.querySources()
if(!this.resultLimits.scrollComplete) {
this.querySources()
}
}
//OLD FUNCTIONS

View File

@ -1,16 +1,23 @@
import { Injectable } from '@angular/core';
import {FormBuilder, FormControl, FormGroup} from '@angular/forms';
import {debounceTime} from 'rxjs/operators';
import {debounceTime, pairwise, startWith} from 'rxjs/operators';
import {Router} from '@angular/router';
import * as _ from 'lodash';
import {BehaviorSubject} from 'rxjs';
export class MedicalSourcesFilter {
searchAfter: string | string[] = '';
//primary search terms (changes here should restart the search completely)
query: string;
//secondary search terms/facets (changes here should restart pagination)
platformTypes: string[] = [];
categories: string[] = [];
showHidden: boolean = false;
//pagination - this is the current page (changes here should be ignored)
searchAfter: string | string[] = '';
fields: string[] = []; //specify the fields to return. if null or empty list, return all.
}
@ -27,24 +34,90 @@ export class MedicalSourcesFilterService {
showHidden: [false],
})
filterChanges = new BehaviorSubject<{filter: MedicalSourcesFilter, changed:string[] }>(null);
constructor(
private formBuilder: FormBuilder,
private router: Router,
// private router: Router,
) {
//changing the form, should change the URL, BUT NOT do a query
this.filterForm.valueChanges.pipe(debounceTime(100)).subscribe(val => {
console.log("FILTER FORM CHANGED:", val, this.toQueryParams())
// //changing the form, should change the URL, BUT NOT do a query
// this.filterForm.valueChanges.pipe(debounceTime(100)).subscribe(val => {
// console.log("FILTER FORM CHANGED:", val, this.toQueryParams())
//
// // change the browser url whenever the filter is updated.
// this.updateBrowserUrl(this.toQueryParams())
// })
// change the browser url whenever the filter is updated.
this.updateBrowserUrl(this.toQueryParams())
})
this.filterForm.valueChanges
//see https://stackoverflow.com/questions/44898010/form-control-valuechanges-gives-the-previous-value
.pipe(startWith(null), pairwise())
.subscribe(pairParams => {
let prevParams = this.toMedicalSourcesFilter(pairParams[0])
let nextParams = this.toMedicalSourcesFilter(pairParams[1])
let changed = [];
//check if primary has changed
if(!_.isEqual(prevParams.query, nextParams.query)){
changed.push('query')
this.resetSecondary();
nextParams.platformTypes = [];
nextParams.categories = [];
nextParams.showHidden = false;
this.resetPagination();
nextParams.searchAfter = ''
//check if secondary/facets have changed
} else if (!_.isEqual(prevParams.platformTypes, nextParams.platformTypes)
|| !_.isEqual(prevParams.categories, nextParams.categories)
|| !_.isEqual(prevParams.showHidden, nextParams.showHidden)
){
if(!_.isEqual(prevParams.platformTypes, nextParams.platformTypes)){
changed.push('platformTypes')
}
if(!_.isEqual(prevParams.categories, nextParams.categories)){
changed.push('categories')
}
if(!_.isEqual(prevParams.showHidden, nextParams.showHidden)){
changed.push('showHidden')
}
this.resetPagination();
nextParams.searchAfter = ''
}
//emit the changes
if (changed.length > 0){
console.log("FILTER FORM - CHANGED:", nextParams, changed)
this.filterChanges.next({
filter: nextParams,
changed: changed
})
} else {
console.log("FILTER FORM - NO CHANGES:", nextParams)
}
})
}
updateBrowserUrl(queryParams: {[name: string]: string}){
console.log("update the browser url with query params data", queryParams)
this.router.navigate(['/sources'], { queryParams: queryParams })
resetPrimary(emit: boolean = false){
this.filterForm.get('query').reset(undefined, {emitEvent: emit});
}
resetSecondary(emit: boolean = false){
this.filterForm.get('platformTypes').reset(undefined, {emitEvent: emit});
this.filterForm.get('categories').reset(undefined, {emitEvent: emit});
this.filterForm.get('showHidden').reset(undefined, {emitEvent: emit});
}
resetPagination(emit: boolean = false){
this.filterForm.get('searchAfter').reset(undefined, {emitEvent: emit});
}
//
// updateBrowserUrl(queryParams: {[name: string]: string}){
// console.log("update the browser url with query params data", queryParams)
// this.router.navigate(['/sources'], { queryParams: queryParams })
// }
resetControl(controlName: string){
this.filterForm.get(controlName).reset();
@ -105,8 +178,10 @@ export class MedicalSourcesFilterService {
return updateData;
}
toQueryParams() : {[name:string]:string} {
var form = this.filterForm.value;
toQueryParams(form) : {[name:string]:string} {
if(!form){
form = this.filterForm.value;
}
var queryParams = {};
@ -156,7 +231,9 @@ export class MedicalSourcesFilterService {
toMedicalSourcesFilter(form): MedicalSourcesFilter {
var medicalSourcesFilter = new MedicalSourcesFilter();
if(!form){
return medicalSourcesFilter
}
if(form.searchAfter){
medicalSourcesFilter.searchAfter = form.searchAfter
}