diff --git a/features/search/search-filters/index.tsx b/features/search/search-filters/index.tsx index 93bfd77e..02b272a7 100644 --- a/features/search/search-filters/index.tsx +++ b/features/search/search-filters/index.tsx @@ -21,12 +21,9 @@ import { TextInput } from "@/components/form/text-input"; import { SearchFilter } from "@/features/search/search-filters/search-filter"; import { SearchContextData } from "@/providers/search-provider"; import { SettingsContext } from "@/providers/settings-provider"; -import { - checkBoxFilterConfigs, - ESRdfType, - ESType, -} from "@/types/entrystore-core"; +import { ESRdfType } from "@/types/entrystore-core"; import { SearchFacet, SearchFacetValue } from "@/types/search"; +import { clearCurrentScrollPos } from "@/utilities/scroll-helper"; import { SearchActiveFilters } from "./search-active-filters"; import { @@ -43,12 +40,6 @@ interface SearchFilterProps { showTip?: boolean; } -interface MarkAllProps { - search: SearchContextData; - toggleKey: string; - title: string; -} - interface FilterSearchProps { filterKey: string; filter: InputFilter; @@ -75,12 +66,6 @@ const FilterSearch: FC = ({ }) => { const { t } = useTranslation("pages"); - const clearCurrentScrollPos = () => { - if (typeof localStorage != "undefined" && typeof location != "undefined") { - localStorage.setItem(`ScrollposY_${location.search}`, "0"); - } - }; - return (
= ({ ); }; -const MarkAll: FC = ({ search, toggleKey, title }) => { - return ( -
- -
- ); -}; - const FindFilters = ( categoryFilters: SearchFacetValue[], checkedFilters: SearchFacetValue[] | undefined, @@ -213,12 +154,6 @@ export const SearchFilters: FC = ({ }; }, [showFilter]); - const clearCurrentScrollPos = () => { - if (typeof localStorage != "undefined" && typeof location != "undefined") { - localStorage.setItem(`ScrollposY_${location.search}`, "0"); - } - }; - const selected = (key: string, facetValue: SearchFacetValue) => { return search.facetSelected(key, facetValue.resource); }; @@ -228,19 +163,6 @@ export const SearchFilters: FC = ({ await search.toggleFacet(facetValue); - if (search.facetSelected(key, "*")) { - const wildcardFacet: SearchFacetValue = { - count: -1, - facet: key, - facetType: ESType.wildcard, - related: false, - facetValueString: "", - resource: "*", - title: t(`filters|allchecktext$${key}`), - }; - await search.toggleFacet(wildcardFacet); - } - await search.doSearch(false, true, false); if (selected(key, facetValue)) { @@ -284,134 +206,6 @@ export const SearchFilters: FC = ({ return grouped; }, [searchMode, search.allFacets]); - const hvd = "http://data.europa.eu/r5r/applicableLegislation"; - const national_data = "http://purl.org/dc/terms/subject"; - const specifications = "http://purl.org/dc/terms/conformsTo"; - - const activeCheckboxFilters = useMemo(() => { - const filters = []; - - // HVD filter - if ( - search.request.facetValues?.some( - (t: SearchFacetValue) => t.title === ESRdfType.hvd, - ) - ) { - filters.push({ - id: "hvd_only", - label: t(`resources|${hvd}`), - facetValue: search.request.facetValues.find( - (t: SearchFacetValue) => t.title === ESRdfType.hvd, - ), - }); - } - - // National filter - if ( - search.request.facetValues?.some( - (t: SearchFacetValue) => t.facet === ESRdfType.national_data, - ) - ) { - filters.push({ - id: "national_only", - label: t(`resources|${national_data}`), - facetValue: search.request.facetValues.find( - (t: SearchFacetValue) => t.facet === ESRdfType.national_data, - ), - }); - } - - // Specification filter - if ( - search.request.facetValues?.some( - (t: SearchFacetValue) => t.facet === ESRdfType.spec, - ) - ) { - filters.push({ - id: "spec_only", - label: t(`resources|${specifications}`), - facetValue: search.request.facetValues.find( - (t) => t.facet === ESRdfType.spec, - ), - }); - } - - // Dataset series filter - if ( - searchMode === "datasets" && - search.request.esRdfTypes?.length === 1 && - search.request.esRdfTypes[0] === ESRdfType.dataset_series - ) { - filters.push({ - id: "dataset_series_only", - label: t(`resources|dataset-series`), - isSpecialFilter: true, - }); - } - - // API only filter - if ( - searchMode === "datasets" && - search.request.esRdfTypes?.some( - (t: ESRdfType) => t === ESRdfType.served_by_data_service, - ) && - search.request.esRdfTypes?.some( - (t: ESRdfType) => t === ESRdfType.data_service, - ) && - !search.request.esRdfTypes?.some( - (t: ESRdfType) => t === ESRdfType.dataset, - ) - ) { - filters.push({ - id: "api_only", - label: t(`resources|api`), - isSpecialFilter: true, - }); - } - - return filters; - }, [search.request.facetValues, search.request.esRdfTypes, searchMode]); - - const handleFilterChange = ( - isApiFilter: boolean, - isChecked: boolean, - currentTypes: ESRdfType[], - ) => { - // Remove all relevant types first - const baseTypes = currentTypes.filter( - (type) => - ![ - ESRdfType.dataset, - ESRdfType.data_service, - ESRdfType.served_by_data_service, - ESRdfType.dataset_series, - ].includes(type), - ); - - // Check which filters are active - const hasApiFilter = isApiFilter - ? !isChecked - : activeCheckboxFilters.some((f) => f.id === "api_only"); - const hasSeriesFilter = !isApiFilter - ? !isChecked - : activeCheckboxFilters.some((f) => f.id === "dataset_series_only"); - - // Build new types array based on filter states - const newTypes = [...baseTypes]; - - if (hasApiFilter) { - newTypes.push(ESRdfType.data_service, ESRdfType.served_by_data_service); - } - if (hasSeriesFilter) { - newTypes.push(ESRdfType.dataset_series); - } - if (!hasApiFilter && !hasSeriesFilter) { - newTypes.push(ESRdfType.dataset); - } - - return newTypes; - }; - return (
= ({ {Object.entries(groupFacets) .sort((a, b) => (a[1].indexOrder > b[1].indexOrder ? 1 : -1)) .map(([key, value], idx: number) => { - const isLicense = false; const shouldFetchMore = value.show <= value.count; const show = (value && value.show) || 20; const facetValues = inputFilter[key] @@ -482,11 +275,7 @@ export const SearchFilters: FC = ({ ) : value?.facetValues.slice(0, show); - if ( - key !== hvd && - key !== national_data && - key !== specifications - ) { + if (!value.customFilter && !value.customSearch) { return (
  • = ({ )} >
    - {(searchMode == "datasets" || - searchMode == "specifications" || - searchMode == "organisations") && ( - //only render on searchpage - <> - {isLicense ? ( - - ) : ( - - shouldFetchMore && - search.fetchMoreFacets(key) - } - /> - )} - - )} + + shouldFetchMore && search.fetchMoreFacets(key) + } + /> + {/* List of filter options within this category */}
      {facetValues @@ -605,108 +379,58 @@ export const SearchFilters: FC = ({ ); } else { - const filterConfig = checkBoxFilterConfigs[key]; return ( filter.id === filterConfig.id, - )} - onChange={() => doSearch(key, facetValues[0])} + id={value.predicate} + name={value.title} + checked={ + value.customFilter + ? search.facetSelected( + key, + value?.customFilter || "", + ) + : value.customSearch?.length === + search.request.esRdfTypes?.length && + value.customSearch?.every( + (type) => + search.request.esRdfTypes?.includes(type), + ) + } + onChange={() => { + if (value.customSearch) { + clearCurrentScrollPos(); + if ( + value.customSearch !== search.request.esRdfTypes + ) { + search + .set({ + esRdfTypes: value.customSearch, + query, + }) + .then(() => search.doSearch()); + } else { + search + .set({ + esRdfTypes: [ + ESRdfType.dataset, + ESRdfType.data_service, + ESRdfType.dataset_series, + ], + query, + }) + .then(() => search.doSearch()); + } + } else { + doSearch(key, facetValues[0]); + } + }} label={t(`resources|${key}`)} iconSize={iconSize} /> ); } })} - - {searchMode == "datasets" && groupName == "distribution" && ( - <> - filter.id === "api_only", - )} - onChange={() => { - clearCurrentScrollPos(); - if ( - activeCheckboxFilters.some( - (filter) => filter.id === "api_only", - ) - ) { - const newTypes = handleFilterChange( - true, - activeCheckboxFilters.some( - (filter) => filter.id === "api_only", - ), - search.request.esRdfTypes || [], - ); - search - .set({ - esRdfTypes: newTypes, - query: query, - }) - .then(() => search.doSearch()); - } else { - search - .set({ - esRdfTypes: [ - ESRdfType.data_service, - ESRdfType.served_by_data_service, - ], - query: query, - }) - .then(() => search.doSearch()); - } - }} - label={t(`resources|api`)} - iconSize={iconSize} - /> - filter.id === "dataset_series_only", - )} - onChange={() => { - clearCurrentScrollPos(); - if ( - activeCheckboxFilters.some( - (filter) => filter.id === "dataset_series_only", - ) - ) { - const newTypes = handleFilterChange( - false, - activeCheckboxFilters.some( - (filter) => filter.id === "dataset_series_only", - ), - search.request.esRdfTypes || [], - ); - search - .set({ - esRdfTypes: newTypes, - query: query, - }) - .then(() => search.doSearch()); - } else { - search - .set({ - esRdfTypes: [ESRdfType.dataset_series], - query: query, - }) - .then(() => search.doSearch()); - } - }} - label={t(`resources|dataset-series`)} - iconSize={iconSize} - /> - - )}
    ))} @@ -716,7 +440,6 @@ export const SearchFilters: FC = ({ search={search} query={query} searchMode={searchMode} - activeCheckboxFilters={activeCheckboxFilters} />
  • @@ -727,7 +450,6 @@ export const SearchFilters: FC = ({ search={search} query={query} searchMode={searchMode} - activeCheckboxFilters={activeCheckboxFilters} />
    ); diff --git a/features/search/search-filters/search-active-filters/index.tsx b/features/search/search-filters/search-active-filters/index.tsx index 3d511f95..f42767a0 100644 --- a/features/search/search-filters/search-active-filters/index.tsx +++ b/features/search/search-filters/search-active-filters/index.tsx @@ -8,6 +8,7 @@ import { SearchContextData } from "@/providers/search-provider"; import { SettingsContext } from "@/providers/settings-provider"; import { ESRdfType } from "@/types/entrystore-core"; import { SearchFacetValue } from "@/types/search"; +import { clearCurrentScrollPos } from "@/utilities/scroll-helper"; import { SearchMode } from "../index"; @@ -15,37 +16,40 @@ interface SearchActiveFiltersProps { search: SearchContextData; query: string; searchMode: SearchMode; - activeCheckboxFilters: Array<{ - id: string; - label: string; - facetValue?: SearchFacetValue; - isSpecialFilter?: boolean; - }>; } export function SearchActiveFilters({ search, query, searchMode, - activeCheckboxFilters, }: SearchActiveFiltersProps) { const { t } = useTranslation(); const { iconSize } = useContext(SettingsContext); - const clearCurrentScrollPos = () => { - if (typeof localStorage != "undefined" && typeof location != "undefined") { - localStorage.setItem(`ScrollposY_${location.search}`, "0"); - } - }; + // Create an array of active special search filters + const activecustomSearchFilters = Object.entries(search.allFacets || {}) + .filter( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ([_, facet]) => + facet.customSearch && + facet.customSearch.length === search.request.esRdfTypes?.length && + facet.customSearch.every( + (type) => search.request.esRdfTypes?.includes(type), + ), + ) + .map(([key, facet]) => ({ + facet: key, + title: facet.title, + customSearch: facet.customSearch, + })); - const hasActiveFilters = () => { - return ( - (search.request.facetValues && search.request.facetValues.length > 0) || - activeCheckboxFilters.length > 0 - ); - }; + const hasActiveFilters = + (search.request.facetValues && search.request.facetValues.length > 0) || + activecustomSearchFilters.length > 0; - if (!hasActiveFilters()) return null; + if (!hasActiveFilters) { + return null; + } return (
    @@ -54,95 +58,110 @@ export function SearchActiveFilters({
    {search.request.facetValues?.map( - (facetValue: SearchFacetValue, index: number) => - facetValue.facet !== - "http://data.europa.eu/r5r/applicableLegislation" && - facetValue.facet !== "http://purl.org/dc/terms/subject" && - facetValue.facet !== "http://purl.org/dc/terms/conformsTo" && ( -
    - - {((search.request.facetValues && - search.request.facetValues.length >= 2) || - activeCheckboxFilters.length >= 2) && ( -
    -
    - )} + ))} + + {search.request.facetValues && + search.request.facetValues.length >= 2 && ( +
    ); } diff --git a/features/search/search-form/index.tsx b/features/search/search-form/index.tsx index 0a96db94..b29fafba 100644 --- a/features/search/search-form/index.tsx +++ b/features/search/search-form/index.tsx @@ -4,6 +4,7 @@ import { Dispatch, SetStateAction, FC } from "react"; import { SearchMode } from "@/features/search/search-filters"; import { SearchInput } from "@/features/search/search-input"; import { SearchContextData } from "@/providers/search-provider"; +import { clearCurrentScrollPos } from "@/utilities/scroll-helper"; interface SearchFormProps { search: SearchContextData; @@ -28,12 +29,6 @@ export const SearchForm: FC = ({ const placeholder = t(`pages|${searchMode}$search`); - const clearCurrentScrollPos = () => { - if (typeof localStorage != "undefined" && typeof location != "undefined") { - localStorage.setItem(`ScrollposY_${location.search}`, "0"); - } - }; - const submitSearch = (newQuery: string) => { search .set({ diff --git a/features/search/search-hit/index.tsx b/features/search/search-hit/index.tsx index f5c981a8..c6844882 100644 --- a/features/search/search-hit/index.tsx +++ b/features/search/search-hit/index.tsx @@ -1,8 +1,6 @@ import Link from "next/link"; -import useTranslation from "next-translate/useTranslation"; import { FC } from "react"; -import { Badge } from "@/components/badge"; import { FileFormatBadge } from "@/components/file-format-badge"; import { Heading } from "@/components/typography/heading"; import { SearchHit as SearchHitType } from "@/types/search"; @@ -13,34 +11,17 @@ interface SearchHitProps { onLinkClick?: () => void; } -const HVD_URI = "http://data.europa.eu/r5r/applicableLegislation"; -const NATIONAL_URI = "http://purl.org/dc/terms/subject"; - -function isHVD(dataset: object) { - return Object.values(dataset).some((ds) => - Object.prototype.hasOwnProperty.call(ds, HVD_URI), - ); -} - -function isNational(dataset: object) { - return Object.values(dataset).some((ds) => - Object.prototype.hasOwnProperty.call(ds, NATIONAL_URI), - ); -} - export const SearchHit: FC = ({ hit, isCompact, onLinkClick, }) => { - const { t } = useTranslation(); - return (
  • = ({ {hit.metadata?.format_literal?.map((m: string, index: number) => ( ))} - {hit.esEntry && isHVD(hit.esEntry._metadata._graph) && ( - - )} - {hit.esEntry && isNational(hit.esEntry._metadata._graph) && ( - - )}
  • diff --git a/features/search/search-page-selector/index.tsx b/features/search/search-page-selector/index.tsx index 27bf2d46..89f6f3d6 100644 --- a/features/search/search-page-selector/index.tsx +++ b/features/search/search-page-selector/index.tsx @@ -52,7 +52,7 @@ export function SearchPageSelector({ query }: SearchTabsProps) { href={`${path}?q=${query || ""}&f=`} label={t(translationKey)} locale={lang} - className={`button--large focus--in whitespace-nowrap rounded-t-md ${ + className={`search-page-selector-button button--large focus--in whitespace-nowrap rounded-t-md ${ pathname === path ? "active" : "" }`} role="tab" diff --git a/features/search/search-page/search-page-content/index.tsx b/features/search/search-page/search-page-content/index.tsx index 487b451f..b27f9cfc 100644 --- a/features/search/search-page/search-page-content/index.tsx +++ b/features/search/search-page/search-page-content/index.tsx @@ -14,6 +14,10 @@ import { SearchHitFragment } from "@/graphql/__generated__/operations"; import { SettingsContext } from "@/providers/settings-provider"; import { SearchHit, SearchRequest, SearchResult } from "@/types/search"; import { linkBase, querySearch } from "@/utilities"; +import { + clearCurrentScrollPos, + saveCurrentScrollPos, +} from "@/utilities/scroll-helper"; interface SearchProps { activeLink?: string; @@ -66,21 +70,6 @@ export const SearchPageContent: FC = () => { setLoading(false); }; - const clearCurrentScrollPos = () => { - if (typeof localStorage != "undefined" && typeof location != "undefined") { - localStorage.setItem(`ScrollposY_${location.search}`, "0"); - } - }; - - const saveCurrentScrollPos = () => { - if (typeof localStorage != "undefined" && typeof location != "undefined") { - localStorage.setItem( - `ScrollposY_${location.search}`, - JSON.stringify(window.scrollY), - ); - } - }; - const highlightWords = (text: string) => { if (!text) return; diff --git a/features/search/search-page/search-page-entryscape/index.tsx b/features/search/search-page/search-page-entryscape/index.tsx index b60b592c..34e4a67c 100644 --- a/features/search/search-page/search-page-entryscape/index.tsx +++ b/features/search/search-page/search-page-entryscape/index.tsx @@ -15,6 +15,7 @@ import { SearchTips } from "@/features/search/search-tips"; import SearchProvider, { SearchContext } from "@/providers/search-provider"; import { SettingsContext } from "@/providers/settings-provider"; import { linkBase } from "@/utilities"; +import { clearCurrentScrollPos } from "@/utilities/scroll-helper"; import { createSearchProviderSettings } from "./search-page-provider-settings"; @@ -25,19 +26,13 @@ interface SearchProps { export const SearchPageEntryscape: FC = ({ searchType }) => { const { env, setBreadcrumb } = useContext(SettingsContext); - const { pathname, query: routerQuery } = useRouter() || {}; + const { pathname } = useRouter() || {}; const { t, lang } = useTranslation(); const [query, setQuery] = useState(""); const [showFilter, setShowFilter] = useState(false); const [showTip, setShowTip] = useState(false); const router = useRouter(); - const clearCurrentScrollPos = () => { - if (typeof localStorage != "undefined") { - localStorage.setItem(`ScrollposY_${routerQuery}`, "0"); - } - }; - useEffect(() => { if (typeof window === "undefined") return; diff --git a/features/search/search-page/search-page-entryscape/search-page-provider-settings.ts b/features/search/search-page/search-page-entryscape/search-page-provider-settings.ts index d15a7027..0ce9c7fa 100644 --- a/features/search/search-page/search-page-entryscape/search-page-provider-settings.ts +++ b/features/search/search-page/search-page-entryscape/search-page-provider-settings.ts @@ -13,6 +13,9 @@ interface FacetConfig { dcatId?: string; related?: boolean; maschineName?: string; + showInSearchResult?: boolean; + customFilter?: string; // Special case for special filters with checkbox + customSearch?: ESRdfType[]; // Special case for special filters with search } interface HitSpecification { @@ -32,7 +35,7 @@ interface SearchProviderConfig { language: string; takeFacets: number; sortOrder?: SearchSortOrder; - // Values to exclude from search + // Values to exclude or include from search filters?: { exclude?: { key: string; @@ -119,7 +122,7 @@ export function createSearchProviderSettings(env: EnvSettings, lang: string) { }, { resource: "http://purl.org/dc/terms/accrualPeriodicity", - dcatId: "dcat:dcterms:accrualPeriodicity_da", + dcatId: "dcat:dcterms:accrualPeriodicity", type: ESType.uri, dcatProperty: "dcterms:accrualPeriodicity", dcatType: "choice", @@ -135,6 +138,8 @@ export function createSearchProviderSettings(env: EnvSettings, lang: string) { dcatFilterEnabled: false, indexOrder: 6, group: "type", + customFilter: "http://data.europa.eu/eli/reg_impl/2023/138/oj", + showInSearchResult: true, }, { resource: "http://purl.org/dc/terms/subject", @@ -142,6 +147,9 @@ export function createSearchProviderSettings(env: EnvSettings, lang: string) { dcatProperty: "dcterms:subject", indexOrder: 7, group: "type", + customFilter: + "http://inspire.ec.europa.eu/metadata-codelist/TopicCategory/*", + showInSearchResult: true, }, { resource: "http://purl.org/dc/terms/conformsTo", @@ -151,6 +159,30 @@ export function createSearchProviderSettings(env: EnvSettings, lang: string) { dcatFilterEnabled: false, indexOrder: 8, group: "type", + customFilter: "*", + }, + { + resource: "http://www.w3.org/ns/dcat#DataService", + type: ESType.uri, + dcatProperty: "dcat:DataService", + dcatType: "choice", + dcatFilterEnabled: false, + indexOrder: 8, + group: "distribution", + customSearch: [ + ESRdfType.data_service, + ESRdfType.served_by_data_service, + ], + }, + { + resource: "http://www.w3.org/ns/dcat#DatasetSeries", + type: ESType.uri, + dcatProperty: "dcat:DatasetSeries", + dcatType: "choice", + dcatFilterEnabled: false, + indexOrder: 9, + group: "distribution", + customSearch: [ESRdfType.dataset_series], }, ], }, @@ -278,13 +310,21 @@ export function createSearchProviderSettings(env: EnvSettings, lang: string) { type: ESType.uri, dcatType: "choice", indexOrder: 1, - maschineName: "publishertype", group: "default", }, + { + resource: "https://www.w3.org/ns/org#classification", + dcatProperty: "org:classification", + type: ESType.uri, + indexOrder: 2, + group: "default", + customFilter: + "https://dataportal.se/concepts/orgAspects/feeFinanzing", + }, ], }, initRequest: { - esRdfTypes: [ESRdfType.agent], + esRdfTypes: [ESRdfType.organisation], language: lang, takeFacets: 30, filters: { diff --git a/features/search/search-results/index.tsx b/features/search/search-results/index.tsx index 65eb1193..cd59d38f 100644 --- a/features/search/search-results/index.tsx +++ b/features/search/search-results/index.tsx @@ -21,6 +21,11 @@ import { SearchContextData, } from "@/providers/search-provider"; import { SettingsContext } from "@/providers/settings-provider"; +import { + clearCurrentScrollPos, + getScrollKey, + saveCurrentScrollPos, +} from "@/utilities/scroll-helper"; interface SearchResultsProps { search: SearchContextData; @@ -44,24 +49,6 @@ const searchFocus = () => { } }; -const SCROLL_POS_PREFIX = "ScrollPosY_" as const; - -function getScrollKey(search: string): string { - return `${SCROLL_POS_PREFIX}${search}`; -} - -function saveCurrentScrollPos(): void { - if (typeof window === "undefined") return; - const key = getScrollKey(window.location.search); - localStorage.setItem(key, window.scrollY.toString()); -} - -function clearCurrentScrollPos(): void { - if (typeof window === "undefined") return; - const key = getScrollKey(window.location.search); - localStorage.removeItem(key); -} - /** * Adds sorting options to the search-results * @@ -76,11 +63,6 @@ const SortingOptions: FC<{ const { t } = useTranslation(); const { iconSize } = useContext(SettingsContext); - const toggleCompact = () => { - clearCurrentScrollPos(); - setCompact(!isCompact); - }; - return (