From b8b2af5fe044887abfb0033336a6b6ec5b2aa6f5 Mon Sep 17 00:00:00 2001 From: pjohans Date: Mon, 19 Feb 2024 09:24:17 +0100 Subject: [PATCH 01/17] in progress - first shot --- .../advancedSearch/facets/advancedFacets.js | 84 ++++++++++++++ .../facets/advancedFacets.module.css | 14 +++ .../facets/advancedFacets.stories.js | 28 +++++ .../search/advancedSearch/facets/curl.txt | 1 + .../advancedSearch/facets/mockedFacets.json | 109 ++++++++++++++++++ .../search/advancedSearch/facets/query.json | 15 +++ .../search/advancedSearch/facets/results.json | 39 +++++++ 7 files changed, 290 insertions(+) create mode 100644 src/components/search/advancedSearch/facets/advancedFacets.js create mode 100644 src/components/search/advancedSearch/facets/advancedFacets.module.css create mode 100644 src/components/search/advancedSearch/facets/advancedFacets.stories.js create mode 100644 src/components/search/advancedSearch/facets/curl.txt create mode 100644 src/components/search/advancedSearch/facets/mockedFacets.json create mode 100644 src/components/search/advancedSearch/facets/query.json create mode 100644 src/components/search/advancedSearch/facets/results.json diff --git a/src/components/search/advancedSearch/facets/advancedFacets.js b/src/components/search/advancedSearch/facets/advancedFacets.js new file mode 100644 index 000000000..6e26b9f81 --- /dev/null +++ b/src/components/search/advancedSearch/facets/advancedFacets.js @@ -0,0 +1,84 @@ +import { AdvFacetsTypeEnum } from "@/lib/enums"; +import Accordion, { Item } from "@/components/base/accordion/Accordion"; +import mockedFacets from "./mockedFacets.json"; +import styles from "./advancedFacets.module.css"; +import { Checkbox } from "@/components/base/forms/checkbox/Checkbox"; +import { useState } from "react"; + +function AdvancedFacets(facets) { + // filter out facets NOT found in request + const filteredFacets = Object.values(AdvFacetsTypeEnum).filter((val) => + facets.find((facet) => { + return facet.name.includes(val); + }) + ); + + return ( + + {filteredFacets.map((facetName, index) => ( + + ))} + + ); +} + +function AccordianItem({ facetName, facets, index }) { + const [selectedItems, setSelectedItems] = useState([]); + // @TODO - use query -> setQuery when checked or unchecked and do a live search + const onItemClick = (checked, name) => { + if (checked) { + // selected -> add to list + const fisk = selectedItems.concat([name]); + setSelectedItems(fisk); + } else { + // not selected -> remove from list + const indx = selectedItems.findIndex((sel) => sel === name); + const fisk = [...selectedItems]; + fisk.splice(indx, 1); + setSelectedItems(fisk); + } + }; + + return ( + + { + return facet.name.includes(facetName); + })} + /> + + ); +} + +function ListItem({ facet, onItemClick }) { + return ( + + ); +} + +export default function wrap() { + // @TODO useData to get REAL data + return AdvancedFacets(mockedFacets.facets); +} diff --git a/src/components/search/advancedSearch/facets/advancedFacets.module.css b/src/components/search/advancedSearch/facets/advancedFacets.module.css new file mode 100644 index 000000000..68578b212 --- /dev/null +++ b/src/components/search/advancedSearch/facets/advancedFacets.module.css @@ -0,0 +1,14 @@ +.item { + border: 1px solid green; + display: grid; + grid-template-columns: 1fr 100fr 100fr; + align-items: center; +} + +.checkbox { + margin-right: var(--pt2); +} + +.score { + text-align: right; +} diff --git a/src/components/search/advancedSearch/facets/advancedFacets.stories.js b/src/components/search/advancedSearch/facets/advancedFacets.stories.js new file mode 100644 index 000000000..8d26fdd58 --- /dev/null +++ b/src/components/search/advancedSearch/facets/advancedFacets.stories.js @@ -0,0 +1,28 @@ +import { StoryTitle, StoryDescription } from "@/storybook"; +import AdvancedFacets from "@/components/search/advancedSearch/facets/advancedFacets"; + +const exportedObject = { + title: "advancedsearch/facets", +}; + +export default exportedObject; + +export function Default() { + return ( +
+ Advanced search facets + + Facets for filtering advanced search result + + +
+ ); +} + +Default.story = { + nextRouter: { + showInfo: true, + pathname: "/avanceret", + query: { cql: "Harry potter" }, + }, +}; diff --git a/src/components/search/advancedSearch/facets/curl.txt b/src/components/search/advancedSearch/facets/curl.txt new file mode 100644 index 000000000..47d8be421 --- /dev/null +++ b/src/components/search/advancedSearch/facets/curl.txt @@ -0,0 +1 @@ +curl -H "Authorization: bearer 7785973fbf75297bc93913c98c10a40011b79011" -H "Content-Type: application/json" -X POST -d 'http://cql-parser.complex-search-prod.svc.cloud.dbc.dk/api/v1' diff --git a/src/components/search/advancedSearch/facets/mockedFacets.json b/src/components/search/advancedSearch/facets/mockedFacets.json new file mode 100644 index 000000000..6b1cb3b4d --- /dev/null +++ b/src/components/search/advancedSearch/facets/mockedFacets.json @@ -0,0 +1,109 @@ +{ + "workIds": [ + "work-of:870970-basis:52035260", + "work-of:870970-basis:27644317", + "work-of:870970-basis:62986115", + "work-of:870970-basis:01671197", + "work-of:870970-basis:05818230", + "work-of:870970-basis:46867394", + "work-of:870970-basis:134579307", + "work-of:870970-basis:07111223", + "work-of:870970-basis:53576885", + "work-of:870970-basis:28768524" + ], + "workdIds": [ + "work-of:870970-basis:52035260", + "work-of:870970-basis:27644317", + "work-of:870970-basis:62986115", + "work-of:870970-basis:01671197", + "work-of:870970-basis:05818230", + "work-of:870970-basis:46867394", + "work-of:870970-basis:134579307", + "work-of:870970-basis:07111223", + "work-of:870970-basis:53576885", + "work-of:870970-basis:28768524" + ], + "solrQuery": "term.title:fisk", + "solrFilter": "{!collapse field=workid} AND ({!terms f=\"collection_identifier\"}150005-analyse,150005-anmeld,150005-artikel,150005-portraet,150008-plus,150021-bibliotek,150021-fjern,150053-turteori,150057-kbebog,150061-ebog,150061-netlydbog,150094-artikel,150096-slaegt,159080-fagbib,159081-fagbib,159082-fagbib,159083-fagbib,159084-fagbib,159085-fagbib,159086-fagbib,800000-accessholdings,800000-bibdk,851680-fagbib,870970-accessholdings,870970-accessmetadata,870970-lokalbibl,870970-udland,870971-avis,870971-faktalink,870971-forfweb,870971-tsart,874310-katalog,911116-katalog)", + "tokenizerDurationInMs": 0, + "solrExecutionDurationInMs": 2601, + "numFound": 5751, + "trackingId": "e5e9f5e8-781a-4339-bc6f-0cc7713666d8", + "facets": [ + { + "name": "phrase.mainlanguage", + "values": [ + { "key": "dansk", "score": 5334 }, + { "key": "engelsk", "score": 90 }, + { "key": "norsk", "score": 75 }, + { "key": "svensk", "score": 57 }, + { "key": "flere sprog", "score": 23 }, + { "key": "tysk", "score": 16 }, + { "key": "sproget kan ikke bestemmes", "score": 15 }, + { "key": "finsk", "score": 6 }, + { "key": "islandsk", "score": 6 }, + { "key": "færøsk", "score": 5 } + ] + }, + { + "name": "phrase.genreandform", + "values": [ + { "key": "opskrifter", "score": 77 }, + { "key": "kogebøger", "score": 64 }, + { "key": "roman", "score": 60 }, + { "key": "eksamensopgaver under disputatsniveau", "score": 31 }, + { "key": "for børn", "score": 29 }, + { "key": "interviews", "score": 27 }, + { "key": "tests", "score": 27 }, + { "key": "dansk pop/rock", "score": 26 }, + { "key": "rock", "score": 23 }, + { "key": "serie", "score": 23 } + ] + }, + { + "name": "phrase.subject", + "values": [ + { "key": "fiskeri", "score": 2782 }, + { "key": "lystfiskeri", "score": 2497 }, + { "key": "fisk", "score": 703 }, + { "key": "fluefiskeri", "score": 520 }, + { "key": "havørredfiskeri", "score": 519 }, + { "key": "havfiskeri", "score": 508 }, + { "key": "kystfiskeri", "score": 504 }, + { "key": "havørred", "score": 418 }, + { "key": "ørredfiskeri", "score": 294 }, + { "key": "danmark", "score": 268 } + ] + }, + { + "name": "phrase.creator", + "values": [ + { "key": "steen ulnits", "score": 254 }, + { "key": "jens bursell", "score": 210 }, + { "key": "niels vestergaard", "score": 121 }, + { "key": "steen larsen", "score": 106 }, + { "key": "gordon p. henriksen", "score": 87 }, + { "key": "lars nielsen", "score": 80 }, + { "key": "jens ploug hansen", "score": 74 }, + { "key": "rasmus hansen", "score": 66 }, + { "key": "per ekstrøm", "score": 64 }, + { "key": "rasmus ovesen", "score": 52 } + ] + }, + { + "name": "phrase.specificmaterialtype", + "values": [ + { "key": "artikel", "score": 4092 }, + { "key": "bog", "score": 1029 }, + { "key": "artikel (online)", "score": 428 }, + { "key": "musik (cd)", "score": 134 }, + { "key": "billedbog", "score": 51 }, + { "key": "tidsskrift", "score": 46 }, + { "key": "node", "score": 41 }, + { "key": "aarbog", "score": 23 }, + { "key": "musik (grammofonplade)", "score": 23 }, + { "key": "e-bog", "score": 22 } + ] + } + ] +} diff --git a/src/components/search/advancedSearch/facets/query.json b/src/components/search/advancedSearch/facets/query.json new file mode 100644 index 000000000..62c2c0b07 --- /dev/null +++ b/src/components/search/advancedSearch/facets/query.json @@ -0,0 +1,15 @@ +{ + "cqlQuery": "term.title='ugle' AND phrase.mainlanguage='dansk'", + "searchProfile": { "agency": "190101", "profile": "bibdk21" }, + "trackingId": "e5e9f5e8-781a-4339-bc6f-0cc7713666d8", + "facetLimit": 10, + "filters": { + "branchId": [ + "775122" + ], + "status": [ + "OnShelf" + ] + }, + "facets": ["phrase.mainlanguage", "phrase.genreandform", "phrase.subject", "phrase.creator", "phrase.specificmaterialtype" ] +} diff --git a/src/components/search/advancedSearch/facets/results.json b/src/components/search/advancedSearch/facets/results.json new file mode 100644 index 000000000..4a94cfa11 --- /dev/null +++ b/src/components/search/advancedSearch/facets/results.json @@ -0,0 +1,39 @@ +{ + "workIds": [ + "work-of:800010-katalog:99122588102905763", + "work-of:800010-katalog:99122870234505763", + "work-of:800010-katalog:99122353244305763", + "work-of:800010-katalog:99122645127105763", + "work-of:870970-basis:10362121" + ], + "workdIds": [ + "work-of:800010-katalog:99122588102905763", + "work-of:800010-katalog:99122870234505763", + "work-of:800010-katalog:99122353244305763", + "work-of:800010-katalog:99122645127105763", + "work-of:870970-basis:10362121" + ], + "solrQuery": "term.title:snemand*", + "solrFilter": "{!collapse field=workid} AND ({!terms f=\"collection_identifier\"}150005-analyse,150005-anmeld,150005-artikel,150005-portraet,150008-plus,150021-bibliotek,150021-fjern,150053-turteori,150057-kbebog,150061-ebog,150061-netlydbog,150094-artikel,150096-slaegt,159080-fagbib,159081-fagbib,159082-fagbib,159083-fagbib,159084-fagbib,159085-fagbib,159086-fagbib,800000-accessholdings,800000-bibdk,851680-fagbib,870970-accessholdings,870970-accessmetadata,870970-lokalbibl,870970-udland,870971-avis,870971-faktalink,870971-forfweb,870971-tsart,874310-katalog,911116-katalog) AND {!parent which=doc_type:manifestation v='branchid:(775122 OR ONLINE-BRANCH-ID) AND status:(onshelf OR ONLINE-STATUS)'}", + "tokenizerDurationInMs": 0, + "solrExecutionDurationInMs": 1754, + "numFound": 272, + "trackingId": "e5e9f5e8-781a-4339-bc6f-0cc7713666d8", + "facets": [ + { + "name": "phrase.language", + "values": [ + { "key": "dansk", "score": 239 }, + { "key": "engelsk", "score": 9 }, + { "key": "norsk", "score": 8 }, + { "key": "svensk", "score": 7 }, + { "key": "finsk", "score": 6 }, + { "key": "spansk", "score": 4 }, + { "key": "tysk", "score": 4 }, + { "key": "fransk", "score": 3 }, + { "key": "sproget kan ikke bestemmes", "score": 3 }, + { "key": "flere sprog", "score": 2 } + ] + } + ] +} From e01cf7ac86d88cedc1dfdaf6ddc7718cbe86efa6 Mon Sep 17 00:00:00 2001 From: pjohans Date: Mon, 19 Feb 2024 09:42:52 +0100 Subject: [PATCH 02/17] in progress - deleted som files --- .../base/forms/checkbox/Checkbox.js | 1 + .../search/advancedSearch/facets/curl.txt | 1 - .../search/advancedSearch/facets/query.json | 15 ------- .../search/advancedSearch/facets/results.json | 39 ------------------- src/lib/enums.js | 9 +++++ 5 files changed, 10 insertions(+), 55 deletions(-) delete mode 100644 src/components/search/advancedSearch/facets/curl.txt delete mode 100644 src/components/search/advancedSearch/facets/query.json delete mode 100644 src/components/search/advancedSearch/facets/results.json diff --git a/src/components/base/forms/checkbox/Checkbox.js b/src/components/base/forms/checkbox/Checkbox.js index 10e1edf2b..678bda016 100644 --- a/src/components/base/forms/checkbox/Checkbox.js +++ b/src/components/base/forms/checkbox/Checkbox.js @@ -96,6 +96,7 @@ Checkbox.propTypes = { required: PropTypes.bool, readOnly: PropTypes.bool, onChange: PropTypes.func, + onClick: PropTypes.func, skeleton: PropTypes.bool, dataCy: PropTypes.string, }; diff --git a/src/components/search/advancedSearch/facets/curl.txt b/src/components/search/advancedSearch/facets/curl.txt deleted file mode 100644 index 47d8be421..000000000 --- a/src/components/search/advancedSearch/facets/curl.txt +++ /dev/null @@ -1 +0,0 @@ -curl -H "Authorization: bearer 7785973fbf75297bc93913c98c10a40011b79011" -H "Content-Type: application/json" -X POST -d 'http://cql-parser.complex-search-prod.svc.cloud.dbc.dk/api/v1' diff --git a/src/components/search/advancedSearch/facets/query.json b/src/components/search/advancedSearch/facets/query.json deleted file mode 100644 index 62c2c0b07..000000000 --- a/src/components/search/advancedSearch/facets/query.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "cqlQuery": "term.title='ugle' AND phrase.mainlanguage='dansk'", - "searchProfile": { "agency": "190101", "profile": "bibdk21" }, - "trackingId": "e5e9f5e8-781a-4339-bc6f-0cc7713666d8", - "facetLimit": 10, - "filters": { - "branchId": [ - "775122" - ], - "status": [ - "OnShelf" - ] - }, - "facets": ["phrase.mainlanguage", "phrase.genreandform", "phrase.subject", "phrase.creator", "phrase.specificmaterialtype" ] -} diff --git a/src/components/search/advancedSearch/facets/results.json b/src/components/search/advancedSearch/facets/results.json deleted file mode 100644 index 4a94cfa11..000000000 --- a/src/components/search/advancedSearch/facets/results.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "workIds": [ - "work-of:800010-katalog:99122588102905763", - "work-of:800010-katalog:99122870234505763", - "work-of:800010-katalog:99122353244305763", - "work-of:800010-katalog:99122645127105763", - "work-of:870970-basis:10362121" - ], - "workdIds": [ - "work-of:800010-katalog:99122588102905763", - "work-of:800010-katalog:99122870234505763", - "work-of:800010-katalog:99122353244305763", - "work-of:800010-katalog:99122645127105763", - "work-of:870970-basis:10362121" - ], - "solrQuery": "term.title:snemand*", - "solrFilter": "{!collapse field=workid} AND ({!terms f=\"collection_identifier\"}150005-analyse,150005-anmeld,150005-artikel,150005-portraet,150008-plus,150021-bibliotek,150021-fjern,150053-turteori,150057-kbebog,150061-ebog,150061-netlydbog,150094-artikel,150096-slaegt,159080-fagbib,159081-fagbib,159082-fagbib,159083-fagbib,159084-fagbib,159085-fagbib,159086-fagbib,800000-accessholdings,800000-bibdk,851680-fagbib,870970-accessholdings,870970-accessmetadata,870970-lokalbibl,870970-udland,870971-avis,870971-faktalink,870971-forfweb,870971-tsart,874310-katalog,911116-katalog) AND {!parent which=doc_type:manifestation v='branchid:(775122 OR ONLINE-BRANCH-ID) AND status:(onshelf OR ONLINE-STATUS)'}", - "tokenizerDurationInMs": 0, - "solrExecutionDurationInMs": 1754, - "numFound": 272, - "trackingId": "e5e9f5e8-781a-4339-bc6f-0cc7713666d8", - "facets": [ - { - "name": "phrase.language", - "values": [ - { "key": "dansk", "score": 239 }, - { "key": "engelsk", "score": 9 }, - { "key": "norsk", "score": 8 }, - { "key": "svensk", "score": 7 }, - { "key": "finsk", "score": 6 }, - { "key": "spansk", "score": 4 }, - { "key": "tysk", "score": 4 }, - { "key": "fransk", "score": 3 }, - { "key": "sproget kan ikke bestemmes", "score": 3 }, - { "key": "flere sprog", "score": 2 } - ] - } - ] -} diff --git a/src/lib/enums.js b/src/lib/enums.js index 8dcc89eb3..1bb4cf4eb 100644 --- a/src/lib/enums.js +++ b/src/lib/enums.js @@ -7,6 +7,15 @@ export const SuggestTypeEnum = Object.freeze({ ALL: "all", }); +export const AdvFacetsTypeEnum = Object.freeze({ + MATERIAL_TYPES: "specificmaterialtype", + SUBJECT: "subject", + CREATORS: "creators", + MAIN_LANGUAGE: "mainlanguage", + GENRE_AND_FORM: "genreAndForm", + CHILDREN_OR_ADULTS: "childrenOrAdults", +}); + export const FilterTypeEnum = Object.freeze({ MATERIAL_TYPES: "materialTypesSpecific", ACCESS_TYPES: "accessTypes", From acc0833cce6b3f6d20d3cd286b35b30cd0510bce Mon Sep 17 00:00:00 2001 From: pjohans Date: Mon, 19 Feb 2024 13:35:20 +0100 Subject: [PATCH 03/17] setFacets --- src/components/search/advancedSearch/facets/advancedFacets.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/search/advancedSearch/facets/advancedFacets.js b/src/components/search/advancedSearch/facets/advancedFacets.js index 6e26b9f81..cd57a04c2 100644 --- a/src/components/search/advancedSearch/facets/advancedFacets.js +++ b/src/components/search/advancedSearch/facets/advancedFacets.js @@ -4,6 +4,7 @@ import mockedFacets from "./mockedFacets.json"; import styles from "./advancedFacets.module.css"; import { Checkbox } from "@/components/base/forms/checkbox/Checkbox"; import { useState } from "react"; +import { useFacets } from "@/components/search/advancedSearch/useFacets"; function AdvancedFacets(facets) { // filter out facets NOT found in request @@ -29,9 +30,12 @@ function AdvancedFacets(facets) { function AccordianItem({ facetName, facets, index }) { const [selectedItems, setSelectedItems] = useState([]); + + const { addFacet } = useFacets(); // @TODO - use query -> setQuery when checked or unchecked and do a live search const onItemClick = (checked, name) => { if (checked) { + addFacet(name, facetName); // selected -> add to list const fisk = selectedItems.concat([name]); setSelectedItems(fisk); From 8d66542b3720e4dde2be8237695fcb2624cf37e3 Mon Sep 17 00:00:00 2001 From: pjohans Date: Tue, 20 Feb 2024 08:08:06 +0100 Subject: [PATCH 04/17] in progress --- .../advancedSearch/facets/advancedFacets.js | 57 ++++++++++--------- .../facets/advancedFacets.stories.js | 5 +- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/components/search/advancedSearch/facets/advancedFacets.js b/src/components/search/advancedSearch/facets/advancedFacets.js index cd57a04c2..04a84aa35 100644 --- a/src/components/search/advancedSearch/facets/advancedFacets.js +++ b/src/components/search/advancedSearch/facets/advancedFacets.js @@ -1,19 +1,38 @@ import { AdvFacetsTypeEnum } from "@/lib/enums"; import Accordion, { Item } from "@/components/base/accordion/Accordion"; -import mockedFacets from "./mockedFacets.json"; + import styles from "./advancedFacets.module.css"; import { Checkbox } from "@/components/base/forms/checkbox/Checkbox"; import { useState } from "react"; import { useFacets } from "@/components/search/advancedSearch/useFacets"; -function AdvancedFacets(facets) { - // filter out facets NOT found in request +/** + * + * @param facets - facet from search result + * @returns {JSX.Element} + * @constructor + */ +export function AdvancedFacets({ facets }) { + // filter out facets NOT found in response const filteredFacets = Object.values(AdvFacetsTypeEnum).filter((val) => facets.find((facet) => { return facet.name.includes(val); }) ); + const { addFacet, removeFacet } = useFacets(); + + // @TODO - use query -> setQuery when checked or unchecked and do a live search + const onItemClick = (checked, name, facetName) => { + if (checked) { + // selected -> add to list + addFacet(name, facetName); + } else { + // deselected - remove from list + removeFacet(name, facetName); + } + }; + return ( {filteredFacets.map((facetName, index) => ( @@ -22,49 +41,35 @@ function AdvancedFacets(facets) { index={index} facets={facets} key={`${facetName}-${index}`} + onItemClick={onItemClick} /> ))} ); } -function AccordianItem({ facetName, facets, index }) { - const [selectedItems, setSelectedItems] = useState([]); - - const { addFacet } = useFacets(); - // @TODO - use query -> setQuery when checked or unchecked and do a live search - const onItemClick = (checked, name) => { - if (checked) { - addFacet(name, facetName); - // selected -> add to list - const fisk = selectedItems.concat([name]); - setSelectedItems(fisk); - } else { - // not selected -> remove from list - const indx = selectedItems.findIndex((sel) => sel === name); - const fisk = [...selectedItems]; - fisk.splice(indx, 1); - setSelectedItems(fisk); - } - }; +function AccordianItem({ facetName, facets, index, onItemClick }) { + // const [selectedItems, setSelectedItems] = useState([]); return ( { return facet.name.includes(facetName); })} + facetName={facetName} /> ); } -function ListItem({ facet, onItemClick }) { +function ListItem({ facet, onItemClick, facetName }) { return (
    {facet.values.map((facet, index) => ( @@ -72,7 +77,7 @@ function ListItem({ facet, onItemClick }) { onItemClick(checked, facet.key)} + onChange={(checked) => onItemClick(checked, facet.key, facetName)} /> {facet.key} {facet.score} @@ -84,5 +89,5 @@ function ListItem({ facet, onItemClick }) { export default function wrap() { // @TODO useData to get REAL data - return AdvancedFacets(mockedFacets.facets); + return AdvancedFacets({}); } diff --git a/src/components/search/advancedSearch/facets/advancedFacets.stories.js b/src/components/search/advancedSearch/facets/advancedFacets.stories.js index 8d26fdd58..33adb3f69 100644 --- a/src/components/search/advancedSearch/facets/advancedFacets.stories.js +++ b/src/components/search/advancedSearch/facets/advancedFacets.stories.js @@ -1,5 +1,6 @@ import { StoryTitle, StoryDescription } from "@/storybook"; -import AdvancedFacets from "@/components/search/advancedSearch/facets/advancedFacets"; +import { AdvancedFacets } from "@/components/search/advancedSearch/facets/advancedFacets"; +import mockedFacets from "./mockedFacets.json"; const exportedObject = { title: "advancedsearch/facets", @@ -14,7 +15,7 @@ export function Default() { Facets for filtering advanced search result - + ); } From 691e40b37d6395cc5be1a803780434617fd6abb8 Mon Sep 17 00:00:00 2001 From: pjohans Date: Tue, 20 Feb 2024 11:23:28 +0100 Subject: [PATCH 05/17] in progress .. write a test --- .../advancedSearch/advancedSearchContext.js | 4 ++ .../advancedSearchResult/topBar/TopBar.js | 5 ++ .../advancedSearch/facets/advancedFacets.js | 4 +- .../facets/advancedFacets.stories.js | 48 +++++++++++++++++-- src/components/search/advancedSearch/utils.js | 38 ++++++++++++++- 5 files changed, 93 insertions(+), 6 deletions(-) diff --git a/src/components/search/advancedSearch/advancedSearchContext.js b/src/components/search/advancedSearch/advancedSearchContext.js index 2eb6fa711..68db3e007 100644 --- a/src/components/search/advancedSearch/advancedSearchContext.js +++ b/src/components/search/advancedSearch/advancedSearchContext.js @@ -16,6 +16,7 @@ import { convertStateToCql } from "@/components/search/advancedSearch/utils"; import { useInputFields } from "@/components/search/advancedSearch/useInputFields"; import { useDropdownSearchIndices } from "@/components/search/advancedSearch/useDropdownSearchIndices"; import isEmpty from "lodash/isEmpty"; +import { useFacets } from "@/components/search/advancedSearch/useFacets"; export function getDefaultDropdownIndices() { return [ @@ -93,6 +94,8 @@ export default function AdvancedSearchProvider({ children, router }) { dispatchResetMenuItemsEvent, } = useDropdownSearchIndices({ ...fieldSearchFromUrl }); + const { selectedFacets } = useFacets(); + //// ---- parsedCQL ---- //only add inputFields to object if there are values const cleanInputFields = @@ -116,6 +119,7 @@ export default function AdvancedSearchProvider({ children, router }) { const updatedCql = convertStateToCql({ inputFields, dropdownSearchIndices, + selectedFacets, }); setParsedCQL(cqlFromUrl || updatedCql); diff --git a/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js b/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js index b09b93144..f0f77d34b 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js +++ b/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js @@ -8,6 +8,8 @@ import Text from "@/components/base/text"; import Translate from "@/components/base/translate"; import isEmpty from "lodash/isEmpty"; import { formattersAndComparitors } from "@/components/search/advancedSearch/useDefaultItemsForDropdownUnits"; +import { getFacetsQuery } from "@/components/search/advancedSearch/utils"; +import { useFacets } from "@/components/search/advancedSearch/useFacets"; /** * @@ -40,6 +42,8 @@ export function FormatFieldSearchIndexes({ fieldsearch }) { (field) => !isEmpty(field.value) ); + const { selectedFacets } = useFacets(); + return (
    0} /> + {getFacetsQuery(selectedFacets)}
    ); } diff --git a/src/components/search/advancedSearch/facets/advancedFacets.js b/src/components/search/advancedSearch/facets/advancedFacets.js index 04a84aa35..92c867422 100644 --- a/src/components/search/advancedSearch/facets/advancedFacets.js +++ b/src/components/search/advancedSearch/facets/advancedFacets.js @@ -20,7 +20,9 @@ export function AdvancedFacets({ facets }) { }) ); - const { addFacet, removeFacet } = useFacets(); + const { addFacet, removeFacet, selectedFacets } = useFacets(); + + console.log(selectedFacets, "SELECTED FACETS"); // @TODO - use query -> setQuery when checked or unchecked and do a live search const onItemClick = (checked, name, facetName) => { diff --git a/src/components/search/advancedSearch/facets/advancedFacets.stories.js b/src/components/search/advancedSearch/facets/advancedFacets.stories.js index 33adb3f69..f784d2f80 100644 --- a/src/components/search/advancedSearch/facets/advancedFacets.stories.js +++ b/src/components/search/advancedSearch/facets/advancedFacets.stories.js @@ -21,9 +21,49 @@ export function Default() { } Default.story = { - nextRouter: { - showInfo: true, - pathname: "/avanceret", - query: { cql: "Harry potter" }, + parameters: { + nextRouter: { + showInfo: true, + pathname: "/avanceret", + query: { cql: "Harry potter" }, + }, + }, +}; + +export function FacetsInUrl() { + return ( +
    + Advanced search facets + + Facets for filtering advanced search result + + +
    + ); +} + +FacetsInUrl.story = { + parameters: { + nextRouter: { + showInfo: true, + pathname: "/avanceret", + query: { + fieldSearch: { + facets: [ + { + searchIndex: "phrase.specificmaterialtype", + values: [ + { value: "e-bog", name: "e-bog" }, + { value: "node", name: "node" }, + ], + }, + { + searchIndex: "phrase.subject", + values: [{ value: "fisk", name: "fisk" }], + }, + ], + }, + }, + }, }, }; diff --git a/src/components/search/advancedSearch/utils.js b/src/components/search/advancedSearch/utils.js index bd26bc8c1..6dede4b4b 100644 --- a/src/components/search/advancedSearch/utils.js +++ b/src/components/search/advancedSearch/utils.js @@ -48,17 +48,53 @@ function getDropdownQuery(dropdownSearchIndices) { ); } -export function convertStateToCql({ inputFields, dropdownSearchIndices } = {}) { +export function getFacetsQuery(facets) { + const OR = LogicalOperatorsEnum.OR; + const AND = LogicalOperatorsEnum.AND; + + return ( + facets + ?.filter((facet) => !isEmpty(facet.values)) + .map((facet) => { + const { getComparator, getFormatValue } = formattersAndComparitors( + facet.searchIndex + ); + + // Each dropdownSearchIndex needs to be joined together. + // For now we use AND with a variable + return facet.values + .map((singleValue) => { + return `${facet.searchIndex}${getComparator?.( + singleValue?.value + )}"${getFormatValue?.(singleValue?.value)}"`; + }) + .join(` ${OR} `); + }) + // Items are wrapped inside parenthesis to ensure precedence + .map((item) => `(${item})`) + .join(` ${AND} `) + ); +} + +export function convertStateToCql({ + inputFields, + dropdownSearchIndices, + facets, +} = {}) { const inputFieldsQuery = getInputFieldsQueryToCql(inputFields); const dropdownQuery = getDropdownQuery(dropdownSearchIndices); + const facetQuery = getFacetsQuery(facets); const AND = LogicalOperatorsEnum.AND; const result = [ ...(!isEmpty(inputFieldsQuery) ? [inputFieldsQuery.join(" ")] : []), ...(!isEmpty(dropdownQuery) ? [dropdownQuery] : []), + ...(!isEmpty(facetQuery) ? [facetQuery] : []), ].join(`) ${AND} (`); + console.log(result, "RESULT"); + return !isEmpty(result) ? "(" + result + ")" : ""; } From 368c8d7263778f22da7a7bc50a4fb5907d7748b2 Mon Sep 17 00:00:00 2001 From: pjohans Date: Tue, 20 Feb 2024 11:23:58 +0100 Subject: [PATCH 06/17] usefacet hook --- .../search/advancedSearch/useFacets.js | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/components/search/advancedSearch/useFacets.js diff --git a/src/components/search/advancedSearch/useFacets.js b/src/components/search/advancedSearch/useFacets.js new file mode 100644 index 000000000..481bb0373 --- /dev/null +++ b/src/components/search/advancedSearch/useFacets.js @@ -0,0 +1,60 @@ +import { useState } from "react"; +import { useRouter } from "next/router"; + +export function useFacets() { + const router = useRouter(); + const [selectedFacets, setSelectedFacets] = useState(facetsFromUrl()); + + /** + * Add an extra facet - we keep facets in a state for + * advanced search context to understand + */ + function addFacet(value, searchindex) { + // check if searchindex is already in facets + const addToIndex = selectedFacets.find((facet) => { + return facet.searchIndex === searchindex; + }); + if (addToIndex !== undefined) { + addToIndex.values.push({ value: value, name: value }); + setSelectedFacets((prev) => { + return [...prev]; + }); + } else { + const newFacets = [ + { + searchIndex: searchindex, + values: [{ value: value, name: value }], + }, + ]; + setSelectedFacets((prev) => { + return [...prev, ...newFacets]; + }); + } + } + + /** + * Remove a facet value from selection + * @param value + * @param searchindex + */ + function removeFacet(value, searchindex) { + // find the overall facet to handle + const indexedFacet = selectedFacets.find((facet) => { + return facet.searchIndex === searchindex; + }); + // find facet(value) in values + const indx = indexedFacet.values.findIndex((val) => val.value === value); + indexedFacet.values.splice(indx, 1); + setSelectedFacets((prev) => { + return [...prev]; + }); + } + + function facetsFromUrl() { + const query = router?.query; + const fieldSearch = query?.fieldSearch && JSON.parse(query?.fieldSearch); + return fieldSearch?.facets || []; + } + + return { selectedFacets, addFacet, removeFacet, facetsFromUrl }; +} From a4ed203745dfa618adf1882e9ff706f43f8eb0bb Mon Sep 17 00:00:00 2001 From: pjohans Date: Wed, 21 Feb 2024 14:01:04 +0100 Subject: [PATCH 07/17] added a test --- e2e/cypress/e2e/advFacets.cy.js | 73 +++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 e2e/cypress/e2e/advFacets.cy.js diff --git a/e2e/cypress/e2e/advFacets.cy.js b/e2e/cypress/e2e/advFacets.cy.js new file mode 100644 index 000000000..f19e2db9b --- /dev/null +++ b/e2e/cypress/e2e/advFacets.cy.js @@ -0,0 +1,73 @@ +describe("Facets", () => { + it(`Get facets from url`, () => { + cy.visit("/iframe.html?id=advancedsearch-facets--facets-in-url"); + + // there should be 3 accordions in this story + cy.get("[data-cy=accordion-item]").should("have.length", 3); + + cy.get("[data-cy=router-query]").then((el) => { + const fisk = JSON.parse(el.text()); + const facets = JSON.parse(fisk.facets); + + // there should be two in query + expect(facets.length).to.equal(2); + }); + + // get the first accordion + cy.get("[data-cy=accordion-item]").first().click(); + + // there should be 10 + cy.get("[data-cy=accordion-item]") + .first() + .find("li") + .should("have.length", 10); + + // two of them should be selected from url params + cy.get("[data-cy=accordion-item]") + .first() + .find("li") + .find("[checked]") + .should("have.length", 2); + + // uncheck one + cy.get("[data-cy=accordion-item]") + .first() + .find("li") + .find("[checked]") + .first() + .focus() + .click({ force: true }); + + // click an item and verify url is updated + cy.get("[data-cy=li-specificmaterialtype-artikel]") + .find("input") + .click({ force: true }); + + cy.get("[data-cy=router-query]").then((el) => { + const fisk = JSON.parse(el.text()); + const facets = fisk.facets; + console.log(facets, "FACETS"); + + expect(facets.includes("artikel")); + }); + + // and again + cy.get("[data-cy=li-specificmaterialtype-aarbog]") + .find("input") + .click({ force: true }); + + cy.get("[data-cy=router-query]").then((el) => { + const fisk = JSON.parse(el.text()); + const facets = fisk.facets; + console.log(facets, "FACETS"); + expect(facets.includes("ufle")); + }); + + // hmm ... this one doesn't work .. i wonder why checked attribute is not updated on checkbox ?? + // cy.get("[data-cy=accordion-item]") + // .first() + // .find("li") + // .find("[checked]") + // .should("have.length", 1); + }); +}); From 2112c485ebf924d94360d5337d81a288ba05088e Mon Sep 17 00:00:00 2001 From: pjohans Date: Wed, 21 Feb 2024 14:01:38 +0100 Subject: [PATCH 08/17] in progress - small steps --- .../advancedSearchResult/topBar/TopBar.js | 2 + .../advancedSearch/facets/advancedFacets.js | 47 ++++++++++++++----- .../facets/advancedFacets.stories.js | 21 ++------- .../search/advancedSearch/useFacets.js | 45 ++++++++++++++---- 4 files changed, 78 insertions(+), 37 deletions(-) diff --git a/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js b/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js index f0f77d34b..76656f842 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js +++ b/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js @@ -44,6 +44,8 @@ export function FormatFieldSearchIndexes({ fieldsearch }) { const { selectedFacets } = useFacets(); + console.log(selectedFacets, "SELECTEDFACESTS"); + return (
    setQuery when checked or unchecked and do a live search const onItemClick = (checked, name, facetName) => { if (checked) { @@ -43,6 +41,7 @@ export function AdvancedFacets({ facets }) { index={index} facets={facets} key={`${facetName}-${index}`} + selectedFacets={selectedFacets} onItemClick={onItemClick} /> ))} @@ -50,36 +49,62 @@ export function AdvancedFacets({ facets }) { ); } -function AccordianItem({ facetName, facets, index, onItemClick }) { - // const [selectedItems, setSelectedItems] = useState([]); +function AccordianItem({ + facetName, + facets, + index, + selectedFacets, + onItemClick, +}) { + const current = selectedFacets?.find((sel) => + sel.searchIndex.includes(facetName) + ); return ( { return facet.name.includes(facetName); })} facetName={facetName} + selectedFacets={selectedFacets} + onItemClick={onItemClick} /> ); } -function ListItem({ facet, onItemClick, facetName }) { +function ListItem({ facet, facetName, selectedFacets, onItemClick }) { + const current = selectedFacets?.find((sel) => + sel?.searchIndex?.includes(facetName) + ); + + let initialcheck; return ( -
      +
        {facet.values.map((facet, index) => ( -
      • +
      • + { + (initialcheck = !!current?.values?.find((val) => { + return val.name === facet.key; + })) + } onItemClick(checked, facet.key, facetName)} + checked={initialcheck} /> {facet.key} {facet.score} diff --git a/src/components/search/advancedSearch/facets/advancedFacets.stories.js b/src/components/search/advancedSearch/facets/advancedFacets.stories.js index f784d2f80..23e67c09f 100644 --- a/src/components/search/advancedSearch/facets/advancedFacets.stories.js +++ b/src/components/search/advancedSearch/facets/advancedFacets.stories.js @@ -34,9 +34,7 @@ export function FacetsInUrl() { return (
        Advanced search facets - - Facets for filtering advanced search result - + Set facets from url
        ); @@ -48,21 +46,8 @@ FacetsInUrl.story = { showInfo: true, pathname: "/avanceret", query: { - fieldSearch: { - facets: [ - { - searchIndex: "phrase.specificmaterialtype", - values: [ - { value: "e-bog", name: "e-bog" }, - { value: "node", name: "node" }, - ], - }, - { - searchIndex: "phrase.subject", - values: [{ value: "fisk", name: "fisk" }], - }, - ], - }, + facets: + '[{"searchIndex": "phrase.specificmaterialtype", "values": [{ "value": "e-bog", "name": "e-bog" },{ "value": "node", "name": "node" } ]},{ "searchIndex": "phrase.subject", "values": [{ "value": "fisk", "name": "fisk" }]}]', }, }, }, diff --git a/src/components/search/advancedSearch/useFacets.js b/src/components/search/advancedSearch/useFacets.js index 481bb0373..216456e4b 100644 --- a/src/components/search/advancedSearch/useFacets.js +++ b/src/components/search/advancedSearch/useFacets.js @@ -12,8 +12,9 @@ export function useFacets() { function addFacet(value, searchindex) { // check if searchindex is already in facets const addToIndex = selectedFacets.find((facet) => { - return facet.searchIndex === searchindex; + return facet.searchIndex.includes(searchindex); }); + if (addToIndex !== undefined) { addToIndex.values.push({ value: value, name: value }); setSelectedFacets((prev) => { @@ -26,10 +27,27 @@ export function useFacets() { values: [{ value: value, name: value }], }, ]; + setSelectedFacets((prev) => { return [...prev, ...newFacets]; }); } + setTimeout(() => { + pushFacetUrl(); + }, 300); + } + + function pushFacetUrl() { + if (selectedFacets.length < 1) { + return null; + } + + const query = router?.query; + query["facets"] = JSON.stringify(selectedFacets); + router.push({ + pathname: router.pathname, + query: query, + }); } /** @@ -39,22 +57,33 @@ export function useFacets() { */ function removeFacet(value, searchindex) { // find the overall facet to handle - const indexedFacet = selectedFacets.find((facet) => { - return facet.searchIndex === searchindex; + const indexedFacet = selectedFacets?.find((facet) => { + return facet.searchIndex.includes(searchindex); }); // find facet(value) in values - const indx = indexedFacet.values.findIndex((val) => val.value === value); - indexedFacet.values.splice(indx, 1); + const indx = indexedFacet?.values?.findIndex((val) => val.value === value); + indexedFacet?.values?.splice(indx, 1); + // @TODO if values are empty -- remove entire facet + if (indexedFacet?.values?.length < 1) { + // @TODO delete + const indexToDelete = selectedFacets?.findIndex((facet) => { + return facet.searchIndex.includes(searchindex); + }); + selectedFacets.splice(indexToDelete, 1); + } setSelectedFacets((prev) => { return [...prev]; }); + + pushFacetUrl(); } function facetsFromUrl() { const query = router?.query; - const fieldSearch = query?.fieldSearch && JSON.parse(query?.fieldSearch); - return fieldSearch?.facets || []; + + const facets = query?.facets && JSON.parse(query?.facets); + return facets || []; } - return { selectedFacets, addFacet, removeFacet, facetsFromUrl }; + return { selectedFacets, addFacet, removeFacet }; } From da4c234357899c5a333010c03371130c5a2dbcbd Mon Sep 17 00:00:00 2001 From: pjohans Date: Thu, 22 Feb 2024 08:51:24 +0100 Subject: [PATCH 09/17] in progress - bugfix + component to style --- e2e/cypress/e2e/advFacets.cy.js | 13 ++------- .../advancedSearch/facets/advancedFacets.js | 14 +++++++-- .../facets/advancedFacets.module.css | 4 +++ .../search/advancedSearch/useFacets.js | 29 +++++++------------ 4 files changed, 29 insertions(+), 31 deletions(-) diff --git a/e2e/cypress/e2e/advFacets.cy.js b/e2e/cypress/e2e/advFacets.cy.js index f19e2db9b..80c4b3765 100644 --- a/e2e/cypress/e2e/advFacets.cy.js +++ b/e2e/cypress/e2e/advFacets.cy.js @@ -48,7 +48,7 @@ describe("Facets", () => { const facets = fisk.facets; console.log(facets, "FACETS"); - expect(facets.includes("artikel")); + assert(facets.includes("artikel")); }); // and again @@ -59,15 +59,8 @@ describe("Facets", () => { cy.get("[data-cy=router-query]").then((el) => { const fisk = JSON.parse(el.text()); const facets = fisk.facets; - console.log(facets, "FACETS"); - expect(facets.includes("ufle")); - }); - // hmm ... this one doesn't work .. i wonder why checked attribute is not updated on checkbox ?? - // cy.get("[data-cy=accordion-item]") - // .first() - // .find("li") - // .find("[checked]") - // .should("have.length", 1); + assert(facets.includes("aarbog")); + }); }); }); diff --git a/src/components/search/advancedSearch/facets/advancedFacets.js b/src/components/search/advancedSearch/facets/advancedFacets.js index d3329e0fb..55bd2baf9 100644 --- a/src/components/search/advancedSearch/facets/advancedFacets.js +++ b/src/components/search/advancedSearch/facets/advancedFacets.js @@ -34,7 +34,7 @@ export function AdvancedFacets({ facets }) { }; return ( - + {filteredFacets.map((facetName, index) => ( { + return ( + <> + {facetName} + {current?.values?.length || ""} + + ); + }; + return ( { - return [...prev, ...newFacets]; + return [...prev]; }); } - setTimeout(() => { - pushFacetUrl(); - }, 300); + + pushFacetUrl(); } function pushFacetUrl() { - if (selectedFacets.length < 1) { - return null; - } - const query = router?.query; query["facets"] = JSON.stringify(selectedFacets); + router.push({ pathname: router.pathname, query: query, @@ -51,7 +46,7 @@ export function useFacets() { } /** - * Remove a facet value from selection + * Remove a facet value from selection and push facets to query * @param value * @param searchindex */ @@ -63,9 +58,7 @@ export function useFacets() { // find facet(value) in values const indx = indexedFacet?.values?.findIndex((val) => val.value === value); indexedFacet?.values?.splice(indx, 1); - // @TODO if values are empty -- remove entire facet if (indexedFacet?.values?.length < 1) { - // @TODO delete const indexToDelete = selectedFacets?.findIndex((facet) => { return facet.searchIndex.includes(searchindex); }); From 55e7781688362c05127720c61930734b44d0a964 Mon Sep 17 00:00:00 2001 From: pjohans Date: Mon, 26 Feb 2024 08:59:38 +0100 Subject: [PATCH 10/17] in progress - facets from enum --- .../base/accordion/Accordion.module.css | 2 +- .../base/animation/expand/Expand.js | 5 +- .../base/animation/expand/Expand.module.css | 6 +-- src/components/base/section/Section.js | 2 +- .../advancedSearch/AdvancedSearch.js | 1 + .../AdvancedSearchResult.js | 41 ++++++++++++-- .../ResultPage/ResultPage.js | 13 ++++- .../cqlErrorMessage/CqlErrorMessage.js | 12 ++++- .../advancedSearch/facets/advancedFacets.js | 54 +++++++++++-------- .../facets/advancedFacets.module.css | 26 +++++++-- .../search/advancedSearch/useFacets.js | 6 ++- src/lib/api/complexSearch.fragments.js | 30 ++++++++--- src/lib/enums.js | 6 +-- 13 files changed, 154 insertions(+), 50 deletions(-) diff --git a/src/components/base/accordion/Accordion.module.css b/src/components/base/accordion/Accordion.module.css index 463a6060b..d1693992f 100644 --- a/src/components/base/accordion/Accordion.module.css +++ b/src/components/base/accordion/Accordion.module.css @@ -93,7 +93,7 @@ } .header_content { - padding: var(--pt2) 0 var(--pt2) 0; + padding: var(--pt1) 0 var(--pt1) 0; } .wrapper { diff --git a/src/components/base/animation/expand/Expand.js b/src/components/base/animation/expand/Expand.js index 890ffb962..7feab196e 100644 --- a/src/components/base/animation/expand/Expand.js +++ b/src/components/base/animation/expand/Expand.js @@ -2,14 +2,15 @@ import Icon from "@/components/base/icon/Icon"; import styles from "./Expand.module.css"; -export default function Expand({ open, size = 3 }) { +export default function Expand({ open, size = 3, src, bgColor }) { return ( {/* Lines to be animated */}
        diff --git a/src/components/base/animation/expand/Expand.module.css b/src/components/base/animation/expand/Expand.module.css index e8acfbbbd..b5b8a3e2b 100644 --- a/src/components/base/animation/expand/Expand.module.css +++ b/src/components/base/animation/expand/Expand.module.css @@ -7,8 +7,8 @@ height: 40%; position: relative; - top: 20%; - left: 20%; + top: 50%; + left: 50%; transform: translate(-50%, -50%); } @@ -20,7 +20,7 @@ width: 100%; - background: white; + background: blue; height: 2px; transition: all 0.35s; } diff --git a/src/components/base/section/Section.js b/src/components/base/section/Section.js index caefc5cb4..184373a64 100644 --- a/src/components/base/section/Section.js +++ b/src/components/base/section/Section.js @@ -119,7 +119,7 @@ export default function Section({ {title && !rightSideTitle && ( diff --git a/src/components/search/advancedSearch/advancedSearch/AdvancedSearch.js b/src/components/search/advancedSearch/advancedSearch/AdvancedSearch.js index 60336660a..8236796ea 100644 --- a/src/components/search/advancedSearch/advancedSearch/AdvancedSearch.js +++ b/src/components/search/advancedSearch/advancedSearch/AdvancedSearch.js @@ -49,6 +49,7 @@ export default function AdvancedSearch({ ariaExpanded, className }) { }, [cqlFromUrl, router?.query?.mode]); //add raw cql query in url if showCqlEditor. Add state to url if fieldInputs + // @TODO add facets here - they can be taken from context :) const doAdvancedSearch = () => { if (showCqlEditor) { const cqlParsedFromUrl = fieldSearchFromUrl diff --git a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js index aeabe4d57..a84433c09 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js +++ b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js @@ -15,6 +15,8 @@ import Title from "@/components/base/title"; import { NoHitSearch } from "@/components/search/advancedSearch/advancedSearchResult/noHitSearch/NoHitSearch"; import ResultPage from "./ResultPage/ResultPage"; import useBreakpoint from "@/components/hooks/useBreakpoint"; +import { AdvancedFacets } from "@/components/search/advancedSearch/facets/advancedFacets"; +import { useFacets } from "@/components/search/advancedSearch/useFacets"; export function AdvancedSearchResult({ pageNo, @@ -23,6 +25,7 @@ export function AdvancedSearchResult({ results, error = null, isLoading, + facets, }) { const hitcount = results?.hitcount; const numPages = Math.ceil(hitcount / 10); @@ -34,21 +37,37 @@ export function AdvancedSearchResult({ return null; } + const TitleComponent = () => { + return ( +
        + {/*
        {hitcount}
        */} + + {hitcount} + + Resultater +
        + ); + }; + return ( <>
        } subtitle={ hitcount > 0 && !isLoading && ( - - {hitcount} - + <> + Afgræns din søgning + + ) } sectionContentClass={isMobile ? styles.sectionContentStyle : ""} @@ -57,6 +76,7 @@ export function AdvancedSearchResult({ {/* Reuse result page from simplesearch - we skip the wrap .. @TODO should we set some mark .. that we are doing advanced search .. ?? */} {!isLoading && hitcount === 0 && } + {/**/} <>
        @@ -86,11 +106,13 @@ export function AdvancedSearchResult({ } function parseResponse(bigResponse) { + console.log(bigResponse, "FASTRESPONSE"); return { works: bigResponse?.data?.complexSearch?.works || null, hitcount: bigResponse?.data?.complexSearch?.hitcount || 0, errorMessage: bigResponse?.data?.complexSearch?.errorMessage || null, isLoading: bigResponse?.isLoading, + facets: bigResponse?.data?.complexSearch?.facets, }; } @@ -107,6 +129,8 @@ export default function Wrap({ onWorkClick, onPageChange }) { setShowPopover, } = useAdvancedSearchContext(); + const { facetsFromEnum } = useFacets(); + // @TODO what to do with dataCollect ??? onWorkClick = null; // get setter for advanced search history @@ -119,10 +143,16 @@ export default function Wrap({ onWorkClick, onPageChange }) { const fastResponse = useData( hitcount({ cql: cqlQuery, + facets: { + facetLimit: 5, + facets: facetsFromEnum, + }, }) ); const parsedResponse = parseResponse(fastResponse); + console.log(parsedResponse, "PARSEDRESPONSE"); + //update searchhistory if (!parsedResponse?.errorMessage && !parsedResponse.isLoading) { // make an object for searchhistory @TODO .. the right object please @@ -147,6 +177,7 @@ export default function Wrap({ onWorkClick, onPageChange }) { error={parsedResponse.errorMessage} setShowPopover={setShowPopover} isLoading={parsedResponse.isLoading} + facets={parsedResponse.facets} /> ); } diff --git a/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js b/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js index 176dc7912..8793c5eae 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js +++ b/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js @@ -17,7 +17,7 @@ import isEmpty from "lodash/isEmpty"; * @param {Object} props * See propTypes for specific props and types */ -export function ResultPage({ rows, onWorkClick, isLoading }) { +export function ResultPage({ rows, onWorkClick, isLoading, facets }) { const resultRows = rows?.map((row, index) => ( setQuery when checked or unchecked and do a live search const onItemClick = (checked, name, facetName) => { if (checked) { // selected -> add to list @@ -34,7 +33,7 @@ export function AdvancedFacets({ facets }) { }; return ( - + {filteredFacets.map((facetName, index) => ( { return ( - <> +
        {facetName} - {current?.values?.length || ""} - + {current?.values?.length && ( + {current?.values?.length || ""} + )} +
        ); }; return ( - - { - return facet.name.includes(facetName); - })} - facetName={facetName} - selectedFacets={selectedFacets} - onItemClick={onItemClick} - /> - +
        + + { + return facet.name.includes(facetName); + })} + facetName={facetName} + selectedFacets={selectedFacets} + onItemClick={onItemClick} + /> + +
        ); } @@ -93,10 +96,19 @@ function ListItem({ facet, facetName, selectedFacets, onItemClick }) { sel?.searchIndex?.includes(facetName) ); + // sort - we want selected items first + const sorter = (a) => { + const selected = !!current?.values?.find((val) => { + return val.name === a.key; + }); + + return selected ? -1 : 1; + }; + let initialcheck; return (
          - {facet.values.map((facet, index) => ( + {facet.values.sort(sorter).map((facet, index) => (
        • { @@ -78,5 +82,5 @@ export function useFacets() { return facets || []; } - return { selectedFacets, addFacet, removeFacet }; + return { selectedFacets, addFacet, removeFacet, facetsFromEnum }; } diff --git a/src/lib/api/complexSearch.fragments.js b/src/lib/api/complexSearch.fragments.js index d628e6927..80ba2add4 100644 --- a/src/lib/api/complexSearch.fragments.js +++ b/src/lib/api/complexSearch.fragments.js @@ -8,15 +8,22 @@ import { ApiEnums } from "@/lib/api/api"; * @param limit * @param sort */ -export function doComplexSearchAll({ cql, offset, limit, sort }) { +export function doComplexSearchAll({ cql, offset, limit, sort, facets }) { return { apiUrl: ApiEnums.FBI_API, // delay: 1000, // for debugging query: ` - query ComplexSearchAll($cql: String!, $offset: Int!, $limit: PaginationLimit!, $sort: [Sort!]) { - complexSearch(cql: $cql) { + query ComplexSearchAll($cql: String!, $offset: Int!, $limit: PaginationLimit!, $sort: [Sort!], $facets: complexSearchFacets) { + complexSearch(cql: $cql, facets: $facets) { hitcount errorMessage + facets { + name + values { + key + score + } + } works(offset: $offset, limit: $limit, sort: $sort) { workId mainLanguages { @@ -103,7 +110,7 @@ export function doComplexSearchAll({ cql, offset, limit, sort }) { } } }`, - variables: { cql, offset, limit, sort }, + variables: { cql, offset, limit, sort, facets }, slowThreshold: 3000, }; } @@ -143,17 +150,24 @@ export function complexSearchOnlyWorkIds({ cql, offset, limit, sort }) { * @param limit * @param sort */ -export function hitcount({ cql, offset, limit, sort }) { +export function hitcount({ cql, offset, limit, sort, facets }) { return { apiUrl: ApiEnums.FBI_API, query: ` - query hitcount($cql: String!) { - complexSearch(cql: $cql) { + query hitcount($cql: String!, $facets: complexSearchFacets) { + complexSearch(cql: $cql, facets: $facets) { hitcount errorMessage + facets { + name + values { + key + score + } + } } }`, - variables: { cql, offset, limit, sort }, + variables: { cql, offset, limit, sort, facets }, slowThreshold: 3000, }; } diff --git a/src/lib/enums.js b/src/lib/enums.js index 1bb4cf4eb..4605d74ca 100644 --- a/src/lib/enums.js +++ b/src/lib/enums.js @@ -10,10 +10,10 @@ export const SuggestTypeEnum = Object.freeze({ export const AdvFacetsTypeEnum = Object.freeze({ MATERIAL_TYPES: "specificmaterialtype", SUBJECT: "subject", - CREATORS: "creators", + // CREATORS: "creators", MAIN_LANGUAGE: "mainlanguage", - GENRE_AND_FORM: "genreAndForm", - CHILDREN_OR_ADULTS: "childrenOrAdults", + // GENRE_AND_FORM: "genreAndForm", + // CHILDREN_OR_ADULTS: "childrenOrAdults", }); export const FilterTypeEnum = Object.freeze({ From 75fd4bcabe4f27bae4bd8950332044c2ba931982 Mon Sep 17 00:00:00 2001 From: pjohans Date: Mon, 26 Feb 2024 12:38:51 +0100 Subject: [PATCH 11/17] in progress - remove consoles - find the query --- .../search/advancedSearch/advancedSearchContext.js | 7 ++++--- .../advancedSearchResult/AdvancedSearchResult.js | 3 --- .../advancedSearchResult/ResultPage/ResultPage.js | 1 - .../advancedSearch/advancedSearchResult/topBar/TopBar.js | 2 -- src/components/search/advancedSearch/utils.js | 2 -- 5 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/components/search/advancedSearch/advancedSearchContext.js b/src/components/search/advancedSearch/advancedSearchContext.js index 68db3e007..fc9d94fbc 100644 --- a/src/components/search/advancedSearch/advancedSearchContext.js +++ b/src/components/search/advancedSearch/advancedSearchContext.js @@ -55,9 +55,13 @@ export default function AdvancedSearchProvider({ children, router }) { cql: cqlFromUrl = null, fieldSearch = "", sort: sortFromUrl = "", + facets: facetsFromUrl = "", } = router.query; const fieldSearchFromUrl = fieldSearch && JSON.parse(fieldSearch); const sort = sortFromUrl && JSON.parse(sortFromUrl); + const facets = facetsFromUrl && JSON.parse(facetsFromUrl); + + console.log(facets, "FACETS"); //// ---- Popup Trigger ---- const popoverRef = useRef(null); @@ -94,8 +98,6 @@ export default function AdvancedSearchProvider({ children, router }) { dispatchResetMenuItemsEvent, } = useDropdownSearchIndices({ ...fieldSearchFromUrl }); - const { selectedFacets } = useFacets(); - //// ---- parsedCQL ---- //only add inputFields to object if there are values const cleanInputFields = @@ -119,7 +121,6 @@ export default function AdvancedSearchProvider({ children, router }) { const updatedCql = convertStateToCql({ inputFields, dropdownSearchIndices, - selectedFacets, }); setParsedCQL(cqlFromUrl || updatedCql); diff --git a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js index a84433c09..a948517b4 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js +++ b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js @@ -106,7 +106,6 @@ export function AdvancedSearchResult({ } function parseResponse(bigResponse) { - console.log(bigResponse, "FASTRESPONSE"); return { works: bigResponse?.data?.complexSearch?.works || null, hitcount: bigResponse?.data?.complexSearch?.hitcount || 0, @@ -151,8 +150,6 @@ export default function Wrap({ onWorkClick, onPageChange }) { ); const parsedResponse = parseResponse(fastResponse); - console.log(parsedResponse, "PARSEDRESPONSE"); - //update searchhistory if (!parsedResponse?.errorMessage && !parsedResponse.isLoading) { // make an object for searchhistory @TODO .. the right object please diff --git a/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js b/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js index 8793c5eae..ea93d79f7 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js +++ b/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js @@ -91,7 +91,6 @@ export default function Wrap({ onWorkClick, page }) { }) ); - console.log(bigResponse, "BIGRESPONSE"); const parsedResponse = parseResponse(bigResponse); if (parsedResponse.isLoading) { diff --git a/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js b/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js index 76656f842..f0f77d34b 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js +++ b/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js @@ -44,8 +44,6 @@ export function FormatFieldSearchIndexes({ fieldsearch }) { const { selectedFacets } = useFacets(); - console.log(selectedFacets, "SELECTEDFACESTS"); - return (
          Date: Mon, 26 Feb 2024 14:02:03 +0100 Subject: [PATCH 12/17] in progress - working copy --- .../advancedSearch/advancedSearchContext.js | 6 ++---- .../advancedSearchResult/AdvancedSearchResult.js | 3 ++- .../advancedSearchResult/ResultPage/ResultPage.js | 8 ++++++-- .../advancedSearchResult/topBar/TopBar.js | 4 ++-- src/components/search/advancedSearch/useFacets.js | 6 ++++-- src/components/search/advancedSearch/utils.js | 15 ++++++++------- 6 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/components/search/advancedSearch/advancedSearchContext.js b/src/components/search/advancedSearch/advancedSearchContext.js index fc9d94fbc..863888219 100644 --- a/src/components/search/advancedSearch/advancedSearchContext.js +++ b/src/components/search/advancedSearch/advancedSearchContext.js @@ -16,7 +16,6 @@ import { convertStateToCql } from "@/components/search/advancedSearch/utils"; import { useInputFields } from "@/components/search/advancedSearch/useInputFields"; import { useDropdownSearchIndices } from "@/components/search/advancedSearch/useDropdownSearchIndices"; import isEmpty from "lodash/isEmpty"; -import { useFacets } from "@/components/search/advancedSearch/useFacets"; export function getDefaultDropdownIndices() { return [ @@ -55,14 +54,12 @@ export default function AdvancedSearchProvider({ children, router }) { cql: cqlFromUrl = null, fieldSearch = "", sort: sortFromUrl = "", - facets: facetsFromUrl = "", + facets: facetsFromUrl = "[]", } = router.query; const fieldSearchFromUrl = fieldSearch && JSON.parse(fieldSearch); const sort = sortFromUrl && JSON.parse(sortFromUrl); const facets = facetsFromUrl && JSON.parse(facetsFromUrl); - console.log(facets, "FACETS"); - //// ---- Popup Trigger ---- const popoverRef = useRef(null); const [showPopover, setShowPopover] = useState(false); @@ -173,6 +170,7 @@ export default function AdvancedSearchProvider({ children, router }) { resetObjectState, parsedCQL, setParsedCQL, + facets, fieldSearchFromUrl, cqlFromUrl, pageNoFromUrl: page, diff --git a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js index a948517b4..4a5944368 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js +++ b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js @@ -126,6 +126,7 @@ export default function Wrap({ onWorkClick, onPageChange }) { fieldSearchFromUrl: fieldSearch, pageNoFromUrl: pageNo, setShowPopover, + facets, } = useAdvancedSearchContext(); const { facetsFromEnum } = useFacets(); @@ -134,7 +135,7 @@ export default function Wrap({ onWorkClick, onPageChange }) { onWorkClick = null; // get setter for advanced search history const { setValue } = useAdvancedSearchHistory(); - const cqlQuery = cql || convertStateToCql(fieldSearch); + const cqlQuery = cql || convertStateToCql({ ...fieldSearch, facets: facets }); const showResult = !isEmpty(fieldSearch) || !isEmpty(cql); diff --git a/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js b/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js index ea93d79f7..6bc4266f1 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js +++ b/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js @@ -10,6 +10,7 @@ import { useAdvancedSearchContext } from "@/components/search/advancedSearch/adv import { convertStateToCql } from "@/components/search/advancedSearch/utils"; import isEmpty from "lodash/isEmpty"; +import { useFacets } from "@/components/search/advancedSearch/useFacets"; /** * Row representation of a search result entry @@ -63,13 +64,16 @@ export default function Wrap({ onWorkClick, page }) { cqlFromUrl: cql, fieldSearchFromUrl: fieldSearch, sort, + facets, } = useAdvancedSearchContext(); + const { facetsFromEnum } = useFacets(); + onWorkClick = null; const limit = 10; let offset = limit * (page - 1); - const cqlQuery = cql || convertStateToCql(fieldSearch); + const cqlQuery = cql || convertStateToCql({ ...fieldSearch, facets: facets }); const showResult = !isEmpty(fieldSearch) || !isEmpty(cql); @@ -85,7 +89,7 @@ export default function Wrap({ onWorkClick, page }) { limit: limit, facets: { facetLimit: 5, - facets: ["specificmaterialtype", "subject"], + facets: facetsFromEnum, }, ...(!isEmpty(sort) && { sort: sort }), }) diff --git a/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js b/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js index f0f77d34b..feeb46ffe 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js +++ b/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js @@ -8,7 +8,7 @@ import Text from "@/components/base/text"; import Translate from "@/components/base/translate"; import isEmpty from "lodash/isEmpty"; import { formattersAndComparitors } from "@/components/search/advancedSearch/useDefaultItemsForDropdownUnits"; -import { getFacetsQuery } from "@/components/search/advancedSearch/utils"; +// import { getFacetsQuery } from "@/components/search/advancedSearch/utils"; import { useFacets } from "@/components/search/advancedSearch/useFacets"; /** @@ -54,7 +54,7 @@ export function FormatFieldSearchIndexes({ fieldsearch }) { dropdowns={filteredDropdownSearchIndices} showAndOperator={filteredInputFields?.length > 0} /> - {getFacetsQuery(selectedFacets)} + {/*{getFacetsQuery(selectedFacets)}*/}
          ); } diff --git a/src/components/search/advancedSearch/useFacets.js b/src/components/search/advancedSearch/useFacets.js index bee7357be..c6f2551e8 100644 --- a/src/components/search/advancedSearch/useFacets.js +++ b/src/components/search/advancedSearch/useFacets.js @@ -1,6 +1,7 @@ import { useState } from "react"; import { useRouter } from "next/router"; import { AdvFacetsTypeEnum } from "@/lib/enums"; +import { useAdvancedSearchContext } from "@/components/search/advancedSearch/advancedSearchContext"; export function useFacets() { const router = useRouter(); @@ -39,10 +40,12 @@ export function useFacets() { pushFacetUrl(); } + /** + * Push to query when a facet is added/removed + */ function pushFacetUrl() { const query = router?.query; query["facets"] = JSON.stringify(selectedFacets); - router.push({ pathname: router.pathname, query: query, @@ -77,7 +80,6 @@ export function useFacets() { function facetsFromUrl() { const query = router?.query; - const facets = query?.facets && JSON.parse(query?.facets); return facets || []; } diff --git a/src/components/search/advancedSearch/utils.js b/src/components/search/advancedSearch/utils.js index eb76e0d28..77f092b67 100644 --- a/src/components/search/advancedSearch/utils.js +++ b/src/components/search/advancedSearch/utils.js @@ -1,6 +1,7 @@ import isEmpty from "lodash/isEmpty"; import { LogicalOperatorsEnum } from "@/components/search/enums"; import { formattersAndComparitors } from "@/components/search/advancedSearch/useDefaultItemsForDropdownUnits"; +import { serialize } from "swr/_internal"; function getInputFieldsQueryToCql(inputFields) { return inputFields @@ -51,22 +52,22 @@ function getDropdownQuery(dropdownSearchIndices) { export function getFacetsQuery(facets) { const OR = LogicalOperatorsEnum.OR; const AND = LogicalOperatorsEnum.AND; + const INDEXPREFIX = "phrase."; + + if (isEmpty(facets)) { + return ""; + } return ( facets ?.filter((facet) => !isEmpty(facet.values)) .map((facet) => { - const { getComparator, getFormatValue } = formattersAndComparitors( - facet.searchIndex - ); - + const searchindex = `${INDEXPREFIX}${facet.searchIndex}`; // Each dropdownSearchIndex needs to be joined together. // For now we use AND with a variable return facet.values .map((singleValue) => { - return `${facet.searchIndex}${getComparator?.( - singleValue?.value - )}"${getFormatValue?.(singleValue?.value)}"`; + return `${searchindex}="${singleValue?.value}"`; }) .join(` ${OR} `); }) From 52d3a71e20575f6802cdb32f783cf6bb48f16c19 Mon Sep 17 00:00:00 2001 From: pjohans Date: Tue, 20 Feb 2024 08:36:34 +0100 Subject: [PATCH 13/17] return when request ends --- src/pages/linkme.php.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pages/linkme.php.js b/src/pages/linkme.php.js index 561b0ab80..5d7314033 100644 --- a/src/pages/linkme.php.js +++ b/src/pages/linkme.php.js @@ -133,6 +133,7 @@ LinkmePhp.getInitialProps = async (ctx) => { const path = `/materiale/${title_author}/${workId}#${ctx.query["rec.id"]}`; ctx.res.writeHead(301, { Location: path }); ctx.res.end(); + return; } else { // we do some redirects here - check for cql, ccl, ccl=is (isbn), worldcat links and handle some of it - if // we give up we redirect to old.bibliotek.dk @@ -147,6 +148,7 @@ LinkmePhp.getInitialProps = async (ctx) => { const path = getAdvancedUrl({ type: "isbn", value: isbnnumber }); ctx.res.writeHead(301, { Location: path }); ctx.res.end(); + return; } } @@ -156,6 +158,7 @@ LinkmePhp.getInitialProps = async (ctx) => { const path = `${basePath}${ctx.req["url"]}`; ctx.res.writeHead(301, { Location: path }); ctx.res.end(); + return; } } From 16676792226f0a2713896b5c00ef608084b3d3c9 Mon Sep 17 00:00:00 2001 From: pjohans Date: Tue, 27 Feb 2024 08:40:16 +0100 Subject: [PATCH 14/17] more facets --- .../AdvancedSearchResult.js | 47 +++++++++++++++++-- .../ResultPage/ResultPage.js | 4 +- .../advancedSearch/facets/advancedFacets.js | 20 ++++---- .../search/advancedSearch/useFacets.js | 8 +++- src/lib/enums.js | 30 ++++++++++-- 5 files changed, 87 insertions(+), 22 deletions(-) diff --git a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js index 15e620174..d433abf97 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js +++ b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js @@ -105,13 +105,54 @@ export function AdvancedSearchResult({ ); } +/** + * Complex search returns empty valued facets - values with a score of 0. + * Here we filter out all the empty facet values - and if a facet has none + * values we filter out the entire facet :) + * + * @TODO - should complexsearch filter out the empty values ?? + * + * eg. + * [ + * { + * "key": "brætspil", + * "score": 1 + * }, + * { + * "key": "aarbog", + * "score": 0 + * }, + * { + * "key": "aarbog (cd)", + * "score": 0 + * } + * ] + * + * @param facets + * @returns {*} + */ +function parseOutFacets(facets) { + // find the facet values with a score higher than 0 + const sanitizedFacets = facets + ?.map((facet) => { + return { + name: facet.name, + values: facet.values.filter((value) => value?.score > 0), + }; + }) + // filter out entire facet if there are no values + .filter((facet) => facet.values.length > 0); + + return sanitizedFacets; +} + function parseResponse(bigResponse) { return { works: bigResponse?.data?.complexSearch?.works || null, hitcount: bigResponse?.data?.complexSearch?.hitcount || 0, errorMessage: bigResponse?.data?.complexSearch?.errorMessage || null, isLoading: bigResponse?.isLoading, - facets: bigResponse?.data?.complexSearch?.facets, + facets: parseOutFacets(bigResponse?.data?.complexSearch?.facets), }; } @@ -129,7 +170,7 @@ export default function Wrap({ onWorkClick, onPageChange }) { facets, } = useAdvancedSearchContext(); - const { facetsFromEnum } = useFacets(); + const { facetsFromEnum, facetLimit } = useFacets(); // @TODO what to do with dataCollect ??? onWorkClick = null; @@ -144,7 +185,7 @@ export default function Wrap({ onWorkClick, onPageChange }) { hitcount({ cql: cqlQuery, facets: { - facetLimit: 5, + facetLimit: facetLimit, facets: facetsFromEnum, }, }) diff --git a/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js b/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js index 6bc4266f1..75e18dc49 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js +++ b/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js @@ -67,7 +67,7 @@ export default function Wrap({ onWorkClick, page }) { facets, } = useAdvancedSearchContext(); - const { facetsFromEnum } = useFacets(); + const { facetsFromEnum, facetLimit } = useFacets(); onWorkClick = null; @@ -88,7 +88,7 @@ export default function Wrap({ onWorkClick, page }) { offset: offset, limit: limit, facets: { - facetLimit: 5, + facetLimit: facetLimit, facets: facetsFromEnum, }, ...(!isEmpty(sort) && { sort: sort }), diff --git a/src/components/search/advancedSearch/facets/advancedFacets.js b/src/components/search/advancedSearch/facets/advancedFacets.js index a6fcf729b..ebddd794d 100644 --- a/src/components/search/advancedSearch/facets/advancedFacets.js +++ b/src/components/search/advancedSearch/facets/advancedFacets.js @@ -13,7 +13,7 @@ import { useFacets } from "@/components/search/advancedSearch/useFacets"; * @constructor */ export function AdvancedFacets({ facets }) { - // filter out facets NOT found in response + // filter out emtpyt facets AND facets NOT found in response const filteredFacets = Object.values(AdvFacetsTypeEnum).filter((val) => facets.find((facet) => { return facet.name.includes(val); @@ -108,26 +108,26 @@ function ListItem({ facet, facetName, selectedFacets, onItemClick }) { let initialcheck; return (
            - {facet.values.sort(sorter).map((facet, index) => ( + {facet.values.sort(sorter).map((value, index) => (
          • { (initialcheck = !!current?.values?.find((val) => { - return val.name === facet.key; + return val.name === value.key; })) } onItemClick(checked, facet.key, facetName)} + onChange={(checked) => onItemClick(checked, value.key, facetName)} checked={initialcheck} /> - {facet.key} - {facet.score} + {value.key} + {value.score}
          • ))}
          diff --git a/src/components/search/advancedSearch/useFacets.js b/src/components/search/advancedSearch/useFacets.js index c6f2551e8..e8c32ce08 100644 --- a/src/components/search/advancedSearch/useFacets.js +++ b/src/components/search/advancedSearch/useFacets.js @@ -7,7 +7,9 @@ export function useFacets() { const router = useRouter(); const [selectedFacets, setSelectedFacets] = useState(facetsFromUrl()); - const facetsFromEnum = Object.values(AdvFacetsTypeEnum); + const facetsFromEnum = Object.values(AdvFacetsTypeEnum).map((fac) => + fac.toUpperCase() + ); /** * Add an extra facet and push facets to query - we keep facets in a state for @@ -84,5 +86,7 @@ export function useFacets() { return facets || []; } - return { selectedFacets, addFacet, removeFacet, facetsFromEnum }; + const facetLimit = 10; + + return { selectedFacets, addFacet, removeFacet, facetLimit, facetsFromEnum }; } diff --git a/src/lib/enums.js b/src/lib/enums.js index 4605d74ca..de75bfaaa 100644 --- a/src/lib/enums.js +++ b/src/lib/enums.js @@ -8,12 +8,32 @@ export const SuggestTypeEnum = Object.freeze({ }); export const AdvFacetsTypeEnum = Object.freeze({ - MATERIAL_TYPES: "specificmaterialtype", + AGES: "ages", + // CATALOGUECODE: "cataloguecode", + CONTRIBUTOR: "contributor", + CONTRIBUTORFUNCTION: "contributorfunction", + CREATOR: "creator", + CREATORCONTRIBUTOR: "creatorcontributor", + CREATORCONTRIBUTORFUNCTION: "creatorcontributorfunction", + // CREATORFUNCTION: "creatorfunction", + FICTIONALCHARACTER: "fictionalcharacter", + // FILMNATIONALITY: "filmnationality", + // GAMEPLATFORM: "gameplatform", + GENERALAUDIENCE: "generalaudience", + // GENERALMATERIALTYPE: "generalmaterialtype", + // GENREANDFORM: "genreandform", + // ISSUE: "issue", + LANGUAGE: "language", + // LIBRARYRECOMMENDATION: "libraryrecommendation", + // MAINLANGUAGE: "mainlanguage", + // MUSICALENSEMBLEORCAST: "musicalensembleorcast", + PLAYERS: "players", + // PRIMARYTARGET: "primarytarget", + SPECIFICMATERIALTYPE: "specificmaterialtype", + SPOKENLANGUAGE: "spokenlanguage", + // SUBTITLELANGUAGE: "subtitlelanguage", + // TYPEOFSCORE: "typeofscore", SUBJECT: "subject", - // CREATORS: "creators", - MAIN_LANGUAGE: "mainlanguage", - // GENRE_AND_FORM: "genreAndForm", - // CHILDREN_OR_ADULTS: "childrenOrAdults", }); export const FilterTypeEnum = Object.freeze({ From e8df04336f1948ea52ac53d10252916d9584083c Mon Sep 17 00:00:00 2001 From: pjohans Date: Tue, 27 Feb 2024 09:59:02 +0100 Subject: [PATCH 15/17] some styling + changes from review --- src/components/base/accordion/Accordion.js | 7 ++++++- src/components/base/animation/expand/Expand.js | 11 ++++++++--- .../base/animation/expand/Expand.module.css | 4 ++-- src/components/base/translate/Translate.json | 4 ++++ .../AdvancedSearchResult.js | 14 ++++++++++---- .../AdvancedSearchResult.module.css | 17 +++++++++++++++++ .../ResultPage/ResultPage.js | 4 ---- .../advancedSearchResult/topBar/TopBar.js | 4 ---- .../facets/advancedFacets.module.css | 2 -- 9 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/components/base/accordion/Accordion.js b/src/components/base/accordion/Accordion.js index ddd74ff09..ea90b5ab9 100644 --- a/src/components/base/accordion/Accordion.js +++ b/src/components/base/accordion/Accordion.js @@ -140,7 +140,12 @@ export function Item({
        )}
        - +
        diff --git a/src/components/base/animation/expand/Expand.js b/src/components/base/animation/expand/Expand.js index 7feab196e..c42a3cce5 100644 --- a/src/components/base/animation/expand/Expand.js +++ b/src/components/base/animation/expand/Expand.js @@ -2,15 +2,20 @@ import Icon from "@/components/base/icon/Icon"; import styles from "./Expand.module.css"; -export default function Expand({ open, size = 3, src, bgColor }) { +export default function Expand({ + open, + size = 3, + src = "expand.svg", + bgColor = "var(--blue)", +}) { return ( {/* Lines to be animated */}
        diff --git a/src/components/base/animation/expand/Expand.module.css b/src/components/base/animation/expand/Expand.module.css index b5b8a3e2b..cfc28c2ab 100644 --- a/src/components/base/animation/expand/Expand.module.css +++ b/src/components/base/animation/expand/Expand.module.css @@ -7,8 +7,8 @@ height: 40%; position: relative; - top: 50%; - left: 50%; + top: 20%; + left: 20%; transform: translate(-50%, -50%); } diff --git a/src/components/base/translate/Translate.json b/src/components/base/translate/Translate.json index da6d9f682..4d13c11b4 100644 --- a/src/components/base/translate/Translate.json +++ b/src/components/base/translate/Translate.json @@ -2278,6 +2278,10 @@ "da": "Tilpasses efter materialetype", "en": "Adjusted according to material type" }, + "narrow-search": { + "da": "Afgræns din søgning", + "en": "Narrow your search" + }, "narrow-search-more": { "da": "Afgræns yderligere", "en": "narrow-search-more" diff --git a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js index d433abf97..cb907753a 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js +++ b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js @@ -17,6 +17,7 @@ import ResultPage from "./ResultPage/ResultPage"; import useBreakpoint from "@/components/hooks/useBreakpoint"; import { AdvancedFacets } from "@/components/search/advancedSearch/facets/advancedFacets"; import { useFacets } from "@/components/search/advancedSearch/useFacets"; +import translate from "@/components/base/translate"; export function AdvancedSearchResult({ pageNo, @@ -39,12 +40,13 @@ export function AdvancedSearchResult({ const TitleComponent = () => { return ( -
        - {/*
        {hitcount}
        */} +
        {hitcount} - Resultater + + {translate({ context: "search", label: "title" })} +
        ); }; @@ -65,7 +67,11 @@ export function AdvancedSearchResult({ hitcount > 0 && !isLoading && ( <> - Afgræns din søgning +
        + + {translate({ context: "search", label: "narrow-search" })} + +
        ) diff --git a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.module.css b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.module.css index ec2429ae0..12cb080d7 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.module.css +++ b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.module.css @@ -11,12 +11,29 @@ font-family: var(--body-font-semibold); } +.subtitleStyle { + border-bottom: 1px solid var(--blue); + margin: var(--pt4) 0 var(--pt2) 0; +} + .sectionTitleClass h2 { margin-top: var(--pt2); font-size: 17px; font-family: var(--body-font-semibold); } +.titleflex { + display: flex; + align-items: baseline; + margin-bottom: var(--pt2); + margin-top: var(--pt2); +} + +.countstyle { + color: var(--blue); + margin-right: var(--pt05); +} + .sectionContentStyle { position: relative; top: -55px; diff --git a/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js b/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js index 75e18dc49..fe062036e 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js +++ b/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js @@ -77,10 +77,6 @@ export default function Wrap({ onWorkClick, page }) { const showResult = !isEmpty(fieldSearch) || !isEmpty(cql); - // const facets = { - // facetLimit: 5, - // facets: ["specificmaterialtype", "subject"], - // }; // fetch data for the specific page const bigResponse = useData( doComplexSearchAll({ diff --git a/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js b/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js index f575409ca..3cccaedbc 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js +++ b/src/components/search/advancedSearch/advancedSearchResult/topBar/TopBar.js @@ -8,7 +8,6 @@ import Text from "@/components/base/text"; import Translate from "@/components/base/translate"; import isEmpty from "lodash/isEmpty"; import { formattersAndComparitors } from "@/components/search/advancedSearch/useDefaultItemsForDropdownUnits"; -// import { getFacetsQuery } from "@/components/search/advancedSearch/utils"; import { useFacets } from "@/components/search/advancedSearch/useFacets"; /** @@ -42,8 +41,6 @@ export function FormatFieldSearchIndexes({ fieldsearch }) { (field) => !isEmpty(field.value) ); - const { selectedFacets } = useFacets(); - return (
        0} /> - {/*{getFacetsQuery(selectedFacets)}*/}
        ); } diff --git a/src/components/search/advancedSearch/facets/advancedFacets.module.css b/src/components/search/advancedSearch/facets/advancedFacets.module.css index 89e7c3eba..a6ba2b37c 100644 --- a/src/components/search/advancedSearch/facets/advancedFacets.module.css +++ b/src/components/search/advancedSearch/facets/advancedFacets.module.css @@ -1,5 +1,4 @@ .item { - /*border: 1px solid green;*/ display: grid; grid-template-columns: 1fr 100fr 100fr; align-items: center; @@ -27,7 +26,6 @@ } .accordionContainer { - /*border: 2px solid blue;*/ width: 100%; } From 1acefcb789023c48733918359f4567272ca6d734 Mon Sep 17 00:00:00 2001 From: pjohans Date: Tue, 27 Feb 2024 10:29:20 +0100 Subject: [PATCH 16/17] remove some unused vars --- .../advancedSearch/advancedSearchResult/AdvancedSearchResult.js | 2 +- .../advancedSearchResult/AdvancedSearchResult.module.css | 2 +- .../advancedSearchResult/ResultPage/ResultPage.js | 2 +- .../search/advancedSearch/advancedSearchResult/topBar/TopBar.js | 1 - src/components/search/advancedSearch/useFacets.js | 1 - src/components/search/advancedSearch/utils.js | 1 - 6 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js index cb907753a..c1b9397e9 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js +++ b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.js @@ -44,7 +44,7 @@ export function AdvancedSearchResult({ {hitcount} - + <Title type="title6" className={styles.titleStyle}> {translate({ context: "search", label: "title" })}
        diff --git a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.module.css b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.module.css index 12cb080d7..353697f9a 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.module.css +++ b/src/components/search/advancedSearch/advancedSearchResult/AdvancedSearchResult.module.css @@ -7,11 +7,11 @@ } .titleStyle { - color: var(--blue); font-family: var(--body-font-semibold); } .subtitleStyle { + font-family: var(--body-font-semibold); border-bottom: 1px solid var(--blue); margin: var(--pt4) 0 var(--pt2) 0; } diff --git a/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js b/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js index fe062036e..d17b2d682 100644 --- a/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js +++ b/src/components/search/advancedSearch/advancedSearchResult/ResultPage/ResultPage.js @@ -18,7 +18,7 @@ import { useFacets } from "@/components/search/advancedSearch/useFacets"; * @param {Object} props * See propTypes for specific props and types */ -export function ResultPage({ rows, onWorkClick, isLoading, facets }) { +export function ResultPage({ rows, onWorkClick, isLoading }) { const resultRows = rows?.map((row, index) => ( Date: Tue, 27 Feb 2024 11:11:58 +0100 Subject: [PATCH 17/17] fixed a test + a real error --- e2e/cypress/e2e/advFacets.cy.js | 7 ++++--- .../advancedSearch/cqlErrorMessage/CqlErrorMessage.js | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/e2e/cypress/e2e/advFacets.cy.js b/e2e/cypress/e2e/advFacets.cy.js index 80c4b3765..e1f25694c 100644 --- a/e2e/cypress/e2e/advFacets.cy.js +++ b/e2e/cypress/e2e/advFacets.cy.js @@ -3,7 +3,7 @@ describe("Facets", () => { cy.visit("/iframe.html?id=advancedsearch-facets--facets-in-url"); // there should be 3 accordions in this story - cy.get("[data-cy=accordion-item]").should("have.length", 3); + cy.get("[data-cy=accordion-item]").should("have.length", 4); cy.get("[data-cy=router-query]").then((el) => { const fisk = JSON.parse(el.text()); @@ -24,14 +24,15 @@ describe("Facets", () => { // two of them should be selected from url params cy.get("[data-cy=accordion-item]") - .first() + .eq(2) + .click() .find("li") .find("[checked]") .should("have.length", 2); // uncheck one cy.get("[data-cy=accordion-item]") - .first() + .eq(2) .find("li") .find("[checked]") .first() diff --git a/src/components/search/advancedSearch/cqlErrorMessage/CqlErrorMessage.js b/src/components/search/advancedSearch/cqlErrorMessage/CqlErrorMessage.js index 1825deb0f..6fcf5c8e8 100644 --- a/src/components/search/advancedSearch/cqlErrorMessage/CqlErrorMessage.js +++ b/src/components/search/advancedSearch/cqlErrorMessage/CqlErrorMessage.js @@ -13,6 +13,7 @@ import CloseSvg from "@/public/icons/close_grey.svg"; import RedSvg from "@/public/icons/status__not_for_loan.svg"; import GreenSvg from "@/public/icons/status__on_shelf.svg"; import Translate, { hasTranslation } from "@/components/base/translate"; +import { useFacets } from "@/components/search/advancedSearch/useFacets"; function parseErrorMessage(errorMessage) { // first sentence of errormessage is (kind of) explanation @@ -126,6 +127,7 @@ export function CqlErrorMessage(errormessage) { } export default function Wrap({ cql = "" }) { + const { facetsFromEnum } = useFacets(); const bigResponse = useData( doComplexSearchAll({ cql, @@ -133,7 +135,7 @@ export default function Wrap({ cql = "" }) { limit: 1, facets: { facetLimit: 5, - facets: ["specificmaterialtype", "subject"], + facets: facetsFromEnum, }, }) );