// Import necessary modules, components, and models from Vue and the project import { Component, Vue, Prop } from "vue-facing-decorator"; import VsInput from "@/components/vs-input/vs-input.vue"; import VsResult from "@/components/vs-result/vs-result.vue"; import FacetCategory from "@/components/face-category/facet-category.vue"; import ActiveFacetCategory from "@/components/active-facet-category/active-facet-category.vue"; // Import models and services // import { SolrSettings } from "@/models/solr"; import { OpenSettings } from "@/models/solr"; import DatasetService from "../../services/dataset.service"; import { Suggestion, Dataset, SearchType } from "@/models/dataset"; // import { SolrResponse, FacetFields, FacetItem, FacetResults, FacetInstance } from "@/models/headers"; // import { SolrResponse, FacetFields, FacetItem, FacetResults, FacetInstance, OpenSearchResponse, HitHighlight } from "@/models/headers"; import { FacetItem, FacetResults, OpenSearchResponse } from "@/models/headers"; import { ActiveFilterCategories } from "@/models/solr"; // import { SOLR_HOST, SOLR_CORE } from "@/constants"; import { IPagination } from "@/models/pagination"; import PaginationComponent from "@/components/PaginationComponent.vue"; import { OPEN_HOST, OPEN_CORE } from "@/constants"; // Define the Vue component, its name, and child components @Component({ name: "SearchViewComponent", components: { VsInput, VsResult, FacetCategory, ActiveFacetCategory, PaginationComponent, }, }) // Export the default class for the component export default class SearchViewComponent extends Vue { // Define props passed from the parent component @Prop() display!: string; // Search display string @Prop() type!: string; // Search type // Declare variables used in the component results: Array = []; // Array to hold search results facets: FacetResults = new FacetResults(); // Object to hold facet results searchTerm: string | Suggestion = ""; // The search term input activeFilterCategories: ActiveFilterCategories = new ActiveFilterCategories(); // Active filter categories for search pagination: IPagination = { // Pagination data for the results total: 0, perPage: 10, currentPage: 1, data: [], }; loaded = false; // Boolean to track whether data has been loaded numFound!: number; // Number of results found // private solr: SolrSettings = { // core: SOLR_CORE, //"rdr_data", // SOLR.core; // host: SOLR_HOST, //"tethys.at", // }; // Define settings for the OpenSearch API (core and host information) private open: OpenSettings = { core: OPEN_CORE, host: OPEN_HOST, //"https://catalog.geosphere.at", }; private error = ""; // Computed property to get search term as string get stringSearchTerm(): string { // If searchTerm is a string, return it directly if (typeof this.searchTerm === "string") { return this.searchTerm; // If searchTerm is a Suggestion, return its value and type alias } else if (this.searchTerm instanceof Suggestion) { return this.searchTerm.value + " (" + this.getTypeAlias(this.searchTerm.type) + ")"; // return this.searchTerm.value + " (" + this.searchTerm.type + ")"; // Default to empty string } else { return ""; } } /** * The alias for the search term type will be set depending on the name of the type. * This will allow to display the customised terms instead of the values currently used in the OpenSearch index. * TODO: This should be corrected directly in the index */ getTypeAlias(type: string): string { switch (type) { case "author": return "creator"; case "subjects": return "keyword"; case "doctype": return "data type"; default: return type; } } // Method to check if a search term is present hasSearchTerm(): boolean { if (typeof this.searchTerm === "string" && this.searchTerm !== "") { return true; } else if (this.searchTerm instanceof Suggestion && this.searchTerm.value !== "") { return true; } else { return false; } } // Method to get enum key by enum value getEnumKeyByEnumValue(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 { // Trigger search based on provided display and type props if (this.display != "" && this.type != undefined) { const enumKey: "Title" | "Author" | "Subject" | "Doctype" | null = this.getEnumKeyByEnumValue(SearchType, this.type); if (enumKey) { const suggestion = new Suggestion(this.display, "NO-IDEA", SearchType[enumKey]); // const suggestion = new Suggestion(this.display, "" , SearchType[enumKey]); this.onSearch(suggestion); } else { this.onSearch(this.display); } } else if (this.display != "" && this.type == undefined) { this.onSearch(this.display); } else { this.onSearch(""); } } // Method to trigger a search onSearch(suggestion: Suggestion | string): void { // console.log("ONSEARCH"); // Reset active filter categories and facet results this.activeFilterCategories = new ActiveFilterCategories(); this.facets = new FacetResults(); this.searchTerm = suggestion; // /* 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.facetedSearchSOLR(suggestion, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe({ // next: (res: SolrResponse) => this.dataHandler(res), // error: (error: string) => this.errorHandler(error), // }); DatasetService.facetedSearch(suggestion, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({ next: (res: OpenSearchResponse) => this.dataHandler(res), error: (error: string) => this.errorHandler(error), }); } // Handle the search results private dataHandler(res: OpenSearchResponse, filterItem?: FacetItem): void { this.results = res.hits.hits.map(hit => hit._source); this.numFound = res.hits.total.value; this.pagination.total = res.hits.total.value; this.pagination.perPage = 10; this.pagination.data = this.results; this.pagination.lastPage = Math.ceil(this.pagination.total / this.pagination.perPage); if (res.aggregations) { const facet_fields = res.aggregations; let prop: keyof typeof facet_fields; // Iterate through facet fields for (prop in facet_fields) { const facetCategory = facet_fields[prop]; if (facetCategory.buckets) { const facetItems = facetCategory.buckets.map(bucket => new FacetItem(bucket.key, bucket.doc_count)); 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)) { const indexOfFacetValue = this.facets[prop].findIndex((i) => i.val === facetItem.val); rObj = this.facets[prop][indexOfFacetValue]; rObj.count = facetItem.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(el => el.count > 0); this.facets[prop] = facetValues; } } } } // // Method to handle search response // private dataHandlerSOLR(res: SolrResponse, filterItem?: FacetItem): void { // // console.log("dataHandlerSOLR (docs, numFound):"); // // console.log(res.response.docs); // // console.log(res.response.numFound); // // Update results // this.results = res.response.docs; // this.numFound = res.response.numFound; // // Update pagination // this.pagination["total"] = res.response.numFound; // this.pagination["perPage"] = res.responseHeader.params.rows as number; // this.pagination["data"] = res.response.docs; // this.pagination.lastPage = Math.ceil(this.pagination.total / this.pagination.perPage); // 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) { // const facetItems: Array = facetCategory.buckets; // 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) { console.log("onMenuClick"); this.pagination.currentPage = page; const start = page * this.pagination.perPage - this.pagination.perPage; // // Trigger new search with updated pagination parameters // DatasetService.facetedSearchSOLR(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, start.toString()).subscribe( // (res: SolrResponse) => this.dataHandler(res), // (error: string) => this.errorHandler(error), // ); DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, start.toString()).subscribe({ next: (res: OpenSearchResponse) => this.dataHandler(res), error: (error: string) => this.errorHandler(error), }); } // Method to handle facet filtering onFilter(facetItem: FacetItem): void { console.log("onFilter"); // Reset current page this.pagination.currentPage = 1; // Check if filter item already exists if (!Object.prototype.hasOwnProperty.call(this.activeFilterCategories, facetItem.category)) { this.activeFilterCategories[facetItem.category] = new Array(); } // 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); // DatasetService.facetedSearchSOLR(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe( // (res: SolrResponse) => this.dataHandler(res, facetItem), // (error: string) => this.errorHandler(error), // ); // Trigger new search with updated filter DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({ next: (res: OpenSearchResponse) => this.dataHandler(res, facetItem), error: (error: string) => this.errorHandler(error), }); } } // // // Method to clear facet category filter // onClearFacetCategorySOLR(categoryName: string): void { // console.log("onClearFacetCategory"); // 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; // this.numFound = res.response.numFound; // // pagination // this.pagination["total"] = res.response.numFound; // this.pagination["perPage"] = res.responseHeader.params.rows as number; // this.pagination["currentPage"] = 1; // this.pagination["data"] = res.response.docs; // const facet_fields: FacetFields = res.facets; // let prop: keyof typeof facet_fields; // for (prop in facet_fields) { // const facetCategory: FacetInstance = facet_fields[prop]; // if (facetCategory.buckets) { // const facetItems: Array = facetCategory.buckets; // const facetValues = facetItems.map((facetItem) => { // 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 (prop == categoryName) { // rObj.active = false; // } // } else { // // Create new facet item // rObj = new FacetItem(facetItem.val, facetItem.count); // } // return rObj; // }); // this.facets[prop] = facetValues; // } // } // }, // error: (error: string) => this.errorHandler(error), // complete: () => console.log("clear facet category completed"), // }); // } // Method to clear facet category filter onClearFacetCategory(categoryName: string): void { // console.log("onClearFacetCategory"); delete this.activeFilterCategories[categoryName]; // Trigger new search with updated filter DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({ next: (res: OpenSearchResponse) => { this.results = res.hits.hits.map(hit => hit._source); this.numFound = res.hits.total.value; // Update pagination this.pagination.total = res.hits.total.value; this.pagination.perPage = 10; this.pagination.currentPage = 1; this.pagination.data = this.results; this.pagination.lastPage = Math.ceil(this.pagination.total / this.pagination.perPage); if (res.aggregations) { const facet_fields = res.aggregations; let prop: keyof typeof facet_fields; for (prop in facet_fields) { const facetCategory = facet_fields[prop]; if (facetCategory.buckets) { const facetItems = facetCategory.buckets.map(bucket => new FacetItem(bucket.key, bucket.doc_count)); const facetValues = facetItems.map((facetItem) => { let rObj: FacetItem; if (this.facets[prop]?.some((e) => e.val === facetItem.val)) { // Update existing facet item with new count const indexOfFacetValue = this.facets[prop].findIndex((i) => i.val === facetItem.val); rObj = this.facets[prop][indexOfFacetValue]; rObj.count = facetItem.count; // if facet category 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; }).filter(el => el.count > 0); // Filter out items with count <= 0 this.facets[prop] = facetValues; } } } }, error: (error: string) => this.errorHandler(error), complete: () => console.log("Clear facet category completed"), }); } }