From 81cd7fc8c20502fb3c6556460ef261692f23a7a5 Mon Sep 17 00:00:00 2001 From: JenDiamond Date: Tue, 12 Sep 2023 14:18:23 -0700 Subject: [PATCH] feat: APPS-2054 add search to accessCollections index page (#732) * feat: add search to accessCOllections index page * await * add is and sectionHandle * update icollection access index * comment out for check * update export default * add test * update to collection * update async * feat: updates to elasticsearchplugin and data-api to fix search * fix: get the json from the fetch promise * fix: add few more missing peices for search to work on access collection index * fix: add computed property parseHitResults and add display resulyts count to the template * fix: append ?test to url in the test * fix: use different filed for news category initial commit * fix: news category, as category is of type text in es index due to category field mapped to text fileds like sectionhandle * fix: remove category before indexing and add it back for the page data * fix: revert nuxt.config change --------- Co-authored-by: pghorpade --- cypress/e2e/articlenewslistingpage.cy.js | 2 +- cypress/e2e/collectionsaccesspage.cy.js | 10 ++ gql/queries/CollectionsAccessList.gql | 3 + nuxt.config.js | 2 +- pages/about/news/_slug.vue | 50 ++++-- pages/collections/access/index.vue | 215 +++++++++++++++++++---- pages/help/services-resources/index.vue | 2 +- plugins/elasticsearchplugin.js | 65 +++++-- store/index.js | 10 +- utils/searchConfig.js | 43 ++++- 10 files changed, 333 insertions(+), 69 deletions(-) diff --git a/cypress/e2e/articlenewslistingpage.cy.js b/cypress/e2e/articlenewslistingpage.cy.js index a2ddd3e89..def0a0aca 100644 --- a/cypress/e2e/articlenewslistingpage.cy.js +++ b/cypress/e2e/articlenewslistingpage.cy.js @@ -17,7 +17,7 @@ describe("Article News Listing page", () => { }) it("Visit News Article Listing page filter by category", () => { - cy.visit('/about/news?q=&filters=%7B"category.title.keyword"%3A%5B"Featured"%5D%7D') + cy.visit('/about/news?q=&filters=%7B"articleCategory.title.keyword"%3A%5B"Featured"%5D%7D') cy.get ('h2.about-results').should("be.visible") }) diff --git a/cypress/e2e/collectionsaccesspage.cy.js b/cypress/e2e/collectionsaccesspage.cy.js index 4dea5418b..d59424549 100644 --- a/cypress/e2e/collectionsaccesspage.cy.js +++ b/cypress/e2e/collectionsaccesspage.cy.js @@ -11,4 +11,14 @@ describe("Access Collection page", () => { ) cy.percySnapshot({ widths: [768, 992, 1200] }) }) + it("Search Found", () => { + cy.visit("/collections/access?q=test") + cy.get(".logo-ucla").should("be.visible") + cy.get("input[type=search]").should( + "have.value", + "test" + ) + cy.get("h2.about-results").invoke("text").should("not.be.empty") + //cy.percySnapshot({ widths: [768, 992, 1200] }) + }) }) diff --git a/gql/queries/CollectionsAccessList.gql b/gql/queries/CollectionsAccessList.gql index 686efe976..ba4ee94bb 100644 --- a/gql/queries/CollectionsAccessList.gql +++ b/gql/queries/CollectionsAccessList.gql @@ -4,9 +4,12 @@ query AccessCollectionsListing { text: summary ... on listingAccessCollections_listingAccessCollections_Entry { accessCollections(orderBy: "title") { + id title + slug text: summary uri + sectionHandle externalResourceUrl iconName: illustrationsResourcesAndServices ... on externalResource_externalResource_Entry { diff --git a/nuxt.config.js b/nuxt.config.js index f910f3a14..cbcc602f7 100644 --- a/nuxt.config.js +++ b/nuxt.config.js @@ -97,7 +97,7 @@ export default { */ generate: { // exclude is for npm run genereate uncomment for local builds - // exclude:[/^\/help/,/^\/collections/,/^\/about/,/^\/give/,/^\/impact/], + // exclude:[/^\/help/,/^\/visit/,/^\/give/,/^\/help/,/^\/give/,/^\/impact/], fallback: "404.html", interval: 500, concurrency: 10, diff --git a/pages/about/news/_slug.vue b/pages/about/news/_slug.vue index e3ff0fe52..e543b0d6e 100644 --- a/pages/about/news/_slug.vue +++ b/pages/about/news/_slug.vue @@ -1,5 +1,8 @@ + { alias: '/listing-collections/access', @@ -66,24 +121,83 @@ import removeTags from "~/utils/removeTags" // GQL import ACCESS_COLLECTIONS from "~/gql/queries/CollectionsAccessList.gql" +// UTILITIES +import config from "~/utils/searchConfig" + export default { - async asyncData({ $graphql }) { - const data = await $graphql.default.request(ACCESS_COLLECTIONS) - data.entry.accessCollections.forEach((element) => { - element.to = element.uri ? element.uri : element.externalResourceUrl - element.category = - element.workshopOrEventSeriesType === "help/services-resources" - ? "workshop" - : element.serviceOrResourceType - ? element.serviceOrResourceType - : element.typeHandle === "externalResource" - ? "resource" - : element.typeHandle === "generalContentPage" + async asyncData({ $graphql, $elasticsearchplugin }) { + console.log("In asyncData hook collectionsAccess list") + + const pageAsyncData = await $graphql.default.request(ACCESS_COLLECTIONS) + + if ( + pageAsyncData.entry.accessCollections && + pageAsyncData.entry.accessCollections.length > 0 + ) { + for (let collection of pageAsyncData.entry.accessCollections) { + console.log("Collection indexing:" + collection.slug) + console.log("Collection:" + collection) + collection.searchType = "accessCollections" + collection.to = collection.uri + ? collection.uri + : collection.externalResourceUrl + collection.category = + collection.workshopOrEventSeriesType === + "help/services-resources" + ? "workshop" + : collection.serviceOrResourceType + ? collection.serviceOrResourceType + : collection.typeHandle === "externalResource" ? "resource" - : element.typeHandle - }) + : collection.typeHandle === "generalContentPage" + ? "resource" + : collection.typeHandle + await $elasticsearchplugin.index(collection, collection.slug) + } + } + + return { + page: _get(pageAsyncData, "entry", {}), + } + }, + data() { return { - page: _get(data, "entry", {}), + page: {}, + noResultsFound: false, + hits: [], + searchGenericQuery: { + queryText: this.$route.query.q || "", + }, + } + }, + async fetch() { + this.hits = [] + if (this.$route.query.q && this.$route.query.q !== "") { + const results = await this.$dataApi.keywordSearchWithFilters( + this.$route.query.q || "*", + config.accessCollections.searchFields, + "searchType:accessCollection", + [], + config.accessCollections.sortField, + config.accessCollections.orderBy, + config.accessCollections.resultFields, + [] + ) + this.hits = [] + if (results && results.hits && results.hits.total.value > 0) { + this.hits = results.hits.hits + this.noResultsFound = false + } else { + this.hits = [] + this.noResultsFound = true + } + this.searchGenericQuery = { + queryText: this.$route.query.q || "", + } + } else { + this.hits = [] + this.noResultsFound = false + this.searchGenericQuery = { queryText: "" } } }, head() { @@ -122,6 +236,47 @@ export default { } }) }, + parseHitsResults() { + /*console.log( + "ParseHitsResults checking results data:" + + JSON.stringify(this.hits) + )*/ + return this.parseHits() + }, + }, + fetchOnServer: false, + fetchKey: "collections-access", + watch: { + "$route.query": "$fetch", + "$route.query.q"(newValue) { + console.log("watching queryTEXT: " + newValue) + // if (newValue === "") this.hits = [] + }, + }, + methods: { + parseHits() { + console.log("static mode what is parseHits") + return this.hits.map((obj) => { + console.log( + "What should the category be?:" + + obj["_source"].sectionHandle + ) + return { + ...obj["_source"], + to: obj["_source"].externalResourceUrl + ? obj["_source"].externalResourceUrl + : `/${obj["_source"].uri}`, + } + }) + }, + getSearchData(data) { + this.$router.push({ + path: "/collections/access", + query: { + q: data.text, + }, + }) + }, }, } diff --git a/pages/help/services-resources/index.vue b/pages/help/services-resources/index.vue index b2a056909..c9bf2d7e7 100644 --- a/pages/help/services-resources/index.vue +++ b/pages/help/services-resources/index.vue @@ -372,4 +372,4 @@ export default { text-transform: capitalize; } } - + \ No newline at end of file diff --git a/plugins/elasticsearchplugin.js b/plugins/elasticsearchplugin.js index ac44e2a95..d32bfe863 100644 --- a/plugins/elasticsearchplugin.js +++ b/plugins/elasticsearchplugin.js @@ -1,38 +1,71 @@ - + export default function ({ $config }, inject) { - const esIndex= $config.esTempIndex + const esIndex = $config.esTempIndex async function index(data, slug) { - console.log("elastic search plugin index function :"+esIndex) - try{ - // eslint-disable-next-line no-undef + console.log("elastic search plugin index function :" + esIndex) + try { + // eslint-disable-next-line no-undef if (process.server && process.env.NODE_ENV !== "development" && data && slug && esIndex) { console.log( "this is the elasticsearch plugin: " + JSON.stringify(data) ) - console.warn( "this is the elasticsearch plugin: " + slug ) - const response = await fetch( + // GET Response + const getResponse = await fetch( `${$config.esURL}/${esIndex}/_doc/${slug}`, { headers: { - Authorization: `ApiKey ${$config.esWriteKey}`, - "Content-Type": "application/json", + Authorization: `ApiKey ${$config.esReadKey}`, }, - method: "POST", - body: JSON.stringify(data), } ) - const json = await response.json() - console.warn("Response from ES: "+json) + const getJson = await getResponse.json() + + console.log("Stringified getResponse: " + JSON.stringify(getJson)) + if (getJson && getJson["_source"]) { + console.log("GET-RESPONSE: " + slug) + + const postBody = { + doc: data + } + const updateResponse = await fetch( + `${$config.esURL}/${esIndex}/_update/${slug}`, + { + headers: { + Authorization: `ApiKey ${$config.esWriteKey}`, + "Content-Type": "application/json", + }, + method: "POST", + body: JSON.stringify(postBody), + } + ) + const updateJson = await updateResponse.json() + + console.log("Stringified updateResponse: " + JSON.stringify(updateJson)) + } else { + const response = await fetch( + `${$config.esURL}/${esIndex}/_doc/${slug}`, + { + headers: { + Authorization: `ApiKey ${$config.esWriteKey}`, + "Content-Type": "application/json", + }, + method: "POST", + body: JSON.stringify(data), + } + ) + const json = await response.json() + console.warn("Response from ES: " + JSON.stringify(json)) + } } else { console.warn("not indexing anything") } - }catch (e) { - console.error("skip indexing if connection times out during builds in the mean time: "+e.message) - console.warn("skip indexing if connection times out during builds in the mean time: "+e.message) + } catch (e) { + console.error("skip indexing if connection times out during builds in the mean time: " + e.message) + console.warn("skip indexing if connection times out during builds in the mean time: " + e.message) throw new Error("Elastic Search Indexing failed " + e) // TODO uncomment when cause is clear } } diff --git a/store/index.js b/store/index.js index 095ed9d0f..6dde4692c 100644 --- a/store/index.js +++ b/store/index.js @@ -96,19 +96,19 @@ export const actions = { commit("SET_FOOTER_SOCK", data) return data } catch (e) { - throw new Error("Craft API error, trying to set gobals. " + e) + throw new Error("Craft API error, trying to set globals setFooterSockData. " + e) } }, async setFooterPrimaryData({ commit }, data) { try { if (!data) { data = await this.$graphql.default.request(FOOTER_PRIMARY_ITEMS) - + } commit("SET_FOOTER_PRIMARY", data) return data } catch (e) { - throw new Error("Craft API error, trying to set gobals. " + e) + throw new Error("Craft API error, trying to set globals setFooterPrimary. " + e) } }, async setHeaderData({ commit }, data) { @@ -119,7 +119,7 @@ export const actions = { commit("SET_HEADER", data) return data } catch (e) { - throw new Error("Craft API error, trying to set gobals. " + e) + throw new Error("Craft API error, trying to set globals setHeader. " + e) } }, async getGlobals({ commit }, data) { @@ -139,7 +139,7 @@ export const actions = { commit("SET_GLOBALS", data) return data } catch (e) { - throw new Error("Craft API error, trying to set gobals. " + e) + throw new Error("Craft API error, trying to set globals getGlobals. " + e) } }, } diff --git a/utils/searchConfig.js b/utils/searchConfig.js index 1d8967b17..d5cd139be 100644 --- a/utils/searchConfig.js +++ b/utils/searchConfig.js @@ -61,7 +61,11 @@ const config = { ], }, serviceOrResources: { - searchFields: ["title^6", "summary^6", "text^6"], + searchFields: [ + "title^6", + "summary^6", + "text^6" + ], resultFields: [ "title", "text", @@ -148,12 +152,43 @@ const config = { inputType: "checkbox", }, ], - resultFields: ["title", "text", "physicalDigital", "uri", "heroImage"], + resultFields: [ + "title", + "text", + "physicalDigital", + "uri", + "heroImage" + ], + sortField: "title.keyword", + orderBy: "asc", + }, + accessCollections: { + searchFields: [ + "title^6", + "summary^6", + "text^6" + ], + resultFields: [ + "title", + "uri", + "iconName", + "text", + "summary", + "workshopOrEventSeries", + "externalResourceUrl", + "sectionHandle", + "category", + "serviceOrResourceType", + ], sortField: "title.keyword", orderBy: "asc", }, newsIndex: { - searchFields: ["title^3", "text^3", "contributors*^2"], + searchFields: [ + "title^3", + "text^3", + "contributors*^2" + ], filters: [ { label: "Location", @@ -162,7 +197,7 @@ const config = { }, { label: "Category", - esFieldName: "category.title.keyword", + esFieldName: "articleCategory.title.keyword", inputType: "checkbox", }, ],