CTS link opens in new window. New comments on search related classes and functions

This commit is contained in:
Porras-Bernardez 2024-05-10 15:01:57 +02:00
parent d50bf55fb3
commit d50e93a658
3 changed files with 70 additions and 11 deletions

View File

@ -10,7 +10,7 @@
<a class="navbar-item" href="/">
<!-- <img src="./assets/images/TETHYS-Logo.svg" width="240px" height="86" alt="TETHYS Logo" /> -->
<img src="./assets/images/TETHYS-Logo.svg" width="240" height="86" /> &nbsp;&nbsp;
<a href="https://doi.org/10.34894/TKWVFL"><img src="./assets/images/cts-logo.png" width="80" height="80" /></a>
<a href="https://doi.org/10.34894/TKWVFL" target="_blank"><img src="./assets/images/cts-logo.png" width="80" height="80" /></a>
</a>
<a
id="menu-icon"

View File

@ -16,7 +16,7 @@ class DatasetService {
terms%22%2C%20field%3A%20%22year%22%20%7D&json.facet.author=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22author_facet%22%2C%20limit%3A%20-1%20%7D
*/
// for the autocomplete search
// For the autocomplete search. Method to perform a search based on a term
public searchTerm(term: string, solrCore: string, solrHost: string): Observable<Dataset[]> {
// solr endpoint
const host = "https://" + solrHost;
@ -48,13 +48,14 @@ class DatasetService {
wt: "json",
};
// Make API call to Solr and return the result
const stations = api.get<SolrResponse>(base, q_params).pipe(map((res: SolrResponse) => res.response.docs));
return stations;
}
/* Only one facet => Author: Coric, Stjepan (16)
/* E.g. Only one facet => Author: Coric, Stjepan (16)
https://tethys.at/solr/rdr_data/select?&0=fl%3Did%2Clicence%2Cserver_date_published%2Cabstract_output%2Cidentifier%2Ctitle_output%2Ctitle_additional%2Cauthor%2Csubject%2Cdoctype&q=%2A
&q.op=or&defType=edismax&qf=title%5E3%20author%5E2%20subject%5E1&indent=on&wt=json&rows=10&fq=author%3A%28%22Coric%2C%20Stjepan%22%29&start=0&sort=server_date_published%20desc&facet=on
&json.facet.language=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22language%22%20%7D
@ -62,6 +63,7 @@ class DatasetService {
&json.facet.year=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22year%22%20%7D
&json.facet.author=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22author_facet%22%2C%20limit%3A%20-1%20%7D */
// Method to perform a faceted search
public facetedSearch(
suggestion: Suggestion | string,
activeFilterCategories: ActiveFilterCategories,
@ -69,6 +71,7 @@ class DatasetService {
solrHost: string,
start?: string, // Starting page
): Observable<SolrResponse> {
// Construct Solr query parameters
const host = "https://" + solrHost;
const path = "/solr/" + solrCore + "/select?";
const base = host + path;
@ -86,6 +89,7 @@ class DatasetService {
"doctype",
].toString();
// Determine search term, query operator, and query fields based on the suggestion type
let term, queryOperator, qfFields;
if (typeof suggestion === "string") {
term = suggestion + "*";
@ -97,10 +101,11 @@ class DatasetService {
qfFields = undefined;
}
// Set default value for start if not provided
if (start === undefined) start = "0";
// Construct filter fields based on active filter categories
const filterFields = new Array<string>();
if (Object.keys(activeFilterCategories).length > 0) {
/* Declare variable prop with a type that is a key of the activeFilterCategories. The 'keyof typeof' activeFilterCategories type represents all possible keys
that can exist on the activeFilterCategories --> prop can only be assigned a value that is a key of the activeFilterCategories object */
@ -109,11 +114,13 @@ class DatasetService {
const filterItems = activeFilterCategories[prop];
filterItems.forEach(function (value: string) {
filterFields.push(prop + ':("' + value + '")');
// e.g. Array [ 'subject:("Vektordaten")', 'author:("GeoSphere Austria, ")' ]
});
}
}
// https://solr.apache.org/guide/8_4/json-request-api.html
// Construct Solr query parameters
const q_params = {
"0": "fl=" + fields,
q: term,
@ -135,12 +142,26 @@ class DatasetService {
"json.facet.year": '{ type: "terms", field: "year" }',
"json.facet.author": '{ type: "terms", field: "author_facet", limit: -1 }',
};
/* E.g.
{"0":"fl=id,licence,server_date_published,abstract_output,identifier,title_output,title_additional,author,subject,doctype","q":"*","q.op":"or","defType":"edismax",
"qf":"title^3 author^2 subject^1",
"indent":"on","wt":"json","rows":10,
"fq":["subject:(\"Vektordaten\")","author:(\"GeoSphere Austria, \")"],
"start":"0","sort":"server_date_published desc","facet":"on",
"json.facet.language":"{ type: \"terms\", field: \"language\" }",
"json.facet.subject":"{ type: \"terms\", field: \"subject\", limit: -1 }",
"json.facet.year":"{ type: \"terms\", field: \"year\" }",
"json.facet.author":"{ type: \"terms\", field: \"author_facet\", limit: -1 }"}
*/
// console.log(JSON.stringify(q_params));
// Make API call to Solr and return the result
const stations = api.get<SolrResponse>(base, q_params);
return stations;
}
// Method to fetch years
public getYears(): Observable<string[]> {
const host = VUE_API;
const path = "/api/years";
@ -150,6 +171,7 @@ class DatasetService {
return years;
}
// Method to fetch documents for a specific year
public getDocuments(year: string): Observable<Array<DbDataset>> {
const host = VUE_API;
const path = "/api/sitelinks/" + year;
@ -159,6 +181,7 @@ class DatasetService {
return documents;
}
// Method to fetch a dataset by its ID
public getDataset(id: number): Observable<DbDataset> {
const host = VUE_API;
const path = "/api/dataset/" + id;
@ -168,6 +191,7 @@ class DatasetService {
return dataset;
}
// Method to fetch a dataset by its DOI
public getDatasetByDoi(doi: string): Observable<DbDataset> {
const host = VUE_API;
const path = "/api/dataset/10.24341/tethys." + doi;
@ -177,6 +201,7 @@ class DatasetService {
return dataset;
}
// Method to prepare dataset object
private prepareDataset(datasetObj: DbDataset): DbDataset {
const dataset = deserialize<DbDataset>(DbDataset, JSON.stringify(datasetObj));
dataset.url = document.documentURI;

View File

@ -13,6 +13,7 @@ import { SOLR_HOST, SOLR_CORE } from "@/constants";
import { IPagination } from "@/models/pagination";
import PaginationComponent from "@/components/PaginationComponent.vue";
// Decorate the component and define its name and components
@Component({
name: "SearchViewComponent",
components: {
@ -23,6 +24,8 @@ import PaginationComponent from "@/components/PaginationComponent.vue";
PaginationComponent,
},
})
// Define the SearchViewComponent class
export default class SearchViewComponent extends Vue {
@Prop()
display!: string;
@ -53,6 +56,7 @@ export default class SearchViewComponent extends Vue {
private error = "";
// Computed property to get search term as string
get stringSearchTerm(): string {
if (typeof this.searchTerm === "string") {
return this.searchTerm;
@ -63,6 +67,7 @@ export default class SearchViewComponent extends Vue {
}
}
// Method to check if a search term is present
hasSearchTerm(): boolean {
if (typeof this.searchTerm === "string" && this.searchTerm !== "") {
return true;
@ -75,14 +80,18 @@ export default class SearchViewComponent extends Vue {
// getKeyName(value: string) {
// return Object.entries(Suggestion).find(([key, val]) => val === value)?.[0];
// }
// Method to get enum key by enum value
getEnumKeyByEnumValue<T extends { [index: string]: string }>(myEnum: T, enumValue: string): keyof T | null {
const keys = Object.keys(myEnum).filter((x) => myEnum[x] == enumValue);
return keys.length > 0 ? keys[0] : null;
// return keys[0];
}
// Lifecycle hook: executed before the component is mounted
beforeMount(): void {
// this.rdrAPI = new DatasetService();
// Trigger search based on provided display and type props
if (this.display != "" && this.type != undefined) {
const enumKey: "Title" | "Author" | "Subject" | null = this.getEnumKeyByEnumValue(SearchType, this.type);
if (enumKey) {
@ -98,12 +107,14 @@ export default class SearchViewComponent extends Vue {
}
}
// Method to trigger a search
onSearch(suggestion: Suggestion | string): void {
// Reset active filter categories and facet results
this.activeFilterCategories = new ActiveFilterCategories();
this.facets = new FacetResults();
this.searchTerm = suggestion;
/* The method returns an Observable, and the code subscribes to this Observable to handle the response. If the response is successful, it calls the dataHandler method
/* Perform faceted search. The method returns an Observable, and the code subscribes to this Observable to handle the response. If the response is successful, it calls the dataHandler method
with the Solr response as a parameter. If there is an error, it calls the errorHandler method with the error message as a parameter */
DatasetService.facetedSearch(suggestion, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe({
next: (res: SolrResponse) => this.dataHandler(res),
@ -111,12 +122,13 @@ export default class SearchViewComponent extends Vue {
});
}
// Method to handle search response
private dataHandler(res: SolrResponse, filterItem?: FacetItem): void {
// Update results
this.results = res.response.docs;
this.numFound = res.response.numFound;
// pagination
// Update pagination
this.pagination["total"] = res.response.numFound;
this.pagination["perPage"] = res.responseHeader.params.rows as number;
this.pagination["data"] = res.response.docs;
@ -124,8 +136,11 @@ export default class SearchViewComponent extends Vue {
const facet_fields: FacetFields = res.facets;
/* This code declares a variable prop with a type of keys of the facet_fields object. The keyof typeof facet_fields type represents the keys of the facet_fields object.
This means that prop can only hold values that are keys of the facet_fields object. */
let prop: keyof typeof facet_fields;
// Iterate through facet fields
for (prop in facet_fields) {
const facetCategory = facet_fields[prop];
if (facetCategory.buckets) {
@ -133,55 +148,70 @@ export default class SearchViewComponent extends Vue {
let facetValues = facetItems.map((facetItem) => {
let rObj: FacetItem;
// Check if current facet item matches filter item
if (filterItem?.val == facetItem.val) {
rObj = filterItem;
} else if (this.facets[prop]?.some((e) => e.val === facetItem.val)) {
// console.log(facetValue + " is included")
// Update existing facet item with new count
const indexOfFacetValue = this.facets[prop].findIndex((i) => i.val === facetItem.val);
// console.log(indexOfFacetValue);
rObj = this.facets[prop][indexOfFacetValue];
rObj.count = facetItem.count;
// rObj = new FacetItem(val, count);
} else {
// Create new facet item
rObj = new FacetItem(facetItem.val, facetItem.count);
}
return rObj;
});
// Filter out null values and values with count <= 0
facetValues = facetValues.filter(function (el) {
return el != null && el.count > 0;
});
// this.facets[prop] = facetCategory;
// Update facet values
this.facets[prop] = facetValues;
}
}
}
// Method to handle search errors
private errorHandler(err: string): void {
this.error = err;
}
// Method to handle pagination
onMenuClick(page: number) {
this.pagination.currentPage = page;
const start = page * this.pagination.perPage - this.pagination.perPage;
// Trigger new search with updated pagination parameters
DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, start.toString()).subscribe(
(res: SolrResponse) => this.dataHandler(res),
(error: string) => this.errorHandler(error),
);
}
// Method to handle facet filtering
onFilter(facetItem: FacetItem): void {
// Reset current page
this.pagination.currentPage = 1;
// console.log(facetItem.val);
// if (!this.activeFilterCategories.hasOwnProperty(facetItem.category)) {
// Check if filter item already exists
if (!Object.prototype.hasOwnProperty.call(this.activeFilterCategories, facetItem.category)) {
this.activeFilterCategories[facetItem.category] = new Array<string>();
}
// if (!this.activeFilterCategories[facetItem.category].some((e) => e === facetItem.val)) {
if (!this.activeFilterCategories[facetItem.category].some((e) => e === facetItem.val)) {
this.activeFilterCategories[facetItem.category].push(facetItem.val);
// Check if filter item is not already applied
if (!this.activeFilterCategories[facetItem.category].some((e) => e === facetItem.val)) {
// Add filter item to active filter categories
this.activeFilterCategories[facetItem.category].push(facetItem.val);
// Trigger new search with updated filter
DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe(
(res: SolrResponse) => this.dataHandler(res, facetItem),
(error: string) => this.errorHandler(error),
@ -189,9 +219,11 @@ export default class SearchViewComponent extends Vue {
}
}
// Method to clear facet category filter
onClearFacetCategory(categoryName: string): void {
delete this.activeFilterCategories[categoryName];
// Trigger new search with updated filter
DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe({
next: (res: SolrResponse) => {
this.results = res.response.docs;
@ -214,16 +246,18 @@ export default class SearchViewComponent extends Vue {
let rObj: FacetItem;
if (this.facets[prop]?.some((e) => e.val === facetItem.val)) {
// console.log(facetValue + " is included")
// Update existing facet item with new count
const indexOfFacetValue = this.facets[prop].findIndex((i) => i.val === facetItem.val);
// console.log(indexOfFacetValue);
rObj = this.facets[prop][indexOfFacetValue];
rObj.count = facetItem.count;
// rObj = new FacetItem(val, count);
//if facet ccategory is reactivated category, deactivate all filter items
// if facet ccategory is reactivated category, deactivate all filter items
if (prop == categoryName) {
rObj.active = false;
}
} else {
// Create new facet item
rObj = new FacetItem(facetItem.val, facetItem.count);
}
return rObj;