From 0adb1cda6ad93c4986a9142225cff78564045090 Mon Sep 17 00:00:00 2001 From: ewelinagr Date: Thu, 19 Dec 2024 11:18:46 +0100 Subject: [PATCH 1/6] Fix property ordering in the right panel. --- projects/mercury/src/metadata/common/LinkedDataEntityForm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/mercury/src/metadata/common/LinkedDataEntityForm.js b/projects/mercury/src/metadata/common/LinkedDataEntityForm.js index 2f0b32d45..54ae6f7ab 100644 --- a/projects/mercury/src/metadata/common/LinkedDataEntityForm.js +++ b/projects/mercury/src/metadata/common/LinkedDataEntityForm.js @@ -97,7 +97,7 @@ export const LinkedDataEntityForm = ({ labelFirst, descriptionFirst, systemPropertiesLast, - compareBy(p => (typeof p.order === 'number' ? p.order : Number.MAX_SAFE_INTEGER)), + compareBy(p => (Number.isNaN(Number(p.order)) ? Number.MAX_SAFE_INTEGER : Number(p.order))), compareBy('label') ) ) From 23f630e52b35e0a7c63ea29a29f5b9b7c2770679 Mon Sep 17 00:00:00 2001 From: ewelinagr Date: Thu, 19 Dec 2024 11:19:42 +0100 Subject: [PATCH 2/6] Fix warnings on useDeepCompareEffect hook. --- .../mercury/src/metadata/views/MetadataViewTableContainer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/mercury/src/metadata/views/MetadataViewTableContainer.js b/projects/mercury/src/metadata/views/MetadataViewTableContainer.js index 64fed29f2..0eb4267cb 100644 --- a/projects/mercury/src/metadata/views/MetadataViewTableContainer.js +++ b/projects/mercury/src/metadata/views/MetadataViewTableContainer.js @@ -19,7 +19,7 @@ import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; import CheckBoxIcon from '@mui/icons-material/CheckBox'; import GetAppIcon from '@mui/icons-material/GetApp'; import FormGroup from '@mui/material/FormGroup'; -import useDeepCompareEffect from 'use-deep-compare-effect'; +import useDeepCompareEffect, {useDeepCompareEffectNoCheck} from 'use-deep-compare-effect'; import {useTheme} from '@mui/material/styles'; import type {MetadataViewColumn, MetadataViewFilter} from './MetadataViewAPI'; @@ -376,7 +376,7 @@ export const MetadataViewTableContainer = (props: MetadataViewTableContainerProp setPage(0); }, [filters]); - useDeepCompareEffect(() => { + useDeepCompareEffectNoCheck(() => { resetRowCheckboxes(); }, [data]); From cc596970b34deeb3efd64b1f4dfbf04a6144c115 Mon Sep 17 00:00:00 2001 From: ewelinagr Date: Tue, 31 Dec 2024 09:37:16 +0100 Subject: [PATCH 3/6] Fix metadata endpoint validation error message. --- .../metadata/validation/UniqueLabelValidator.java | 4 +++- .../metadata/validation/ValidationException.java | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/projects/saturn/src/main/java/io/fairspace/saturn/services/metadata/validation/UniqueLabelValidator.java b/projects/saturn/src/main/java/io/fairspace/saturn/services/metadata/validation/UniqueLabelValidator.java index 859673e39..f7e66df11 100644 --- a/projects/saturn/src/main/java/io/fairspace/saturn/services/metadata/validation/UniqueLabelValidator.java +++ b/projects/saturn/src/main/java/io/fairspace/saturn/services/metadata/validation/UniqueLabelValidator.java @@ -7,6 +7,8 @@ import io.fairspace.saturn.vocabulary.FS; +import static org.apache.jena.rdf.model.ResourceFactory.createPlainLiteral; + @Component public class UniqueLabelValidator implements MetadataRequestValidator { @Override @@ -21,7 +23,7 @@ public void validate(Model before, Model after, Model removed, Model added, Viol .filterDrop(res -> res.hasProperty(FS.dateDeleted)) .hasNext(); if (conflictingResourceExists) { - violationHandler.onViolation("Duplicate label", resource, RDFS.label, null); + violationHandler.onViolation("Duplicate label", resource, RDFS.label, createPlainLiteral(label)); } }); } diff --git a/projects/saturn/src/main/java/io/fairspace/saturn/services/metadata/validation/ValidationException.java b/projects/saturn/src/main/java/io/fairspace/saturn/services/metadata/validation/ValidationException.java index 746b2f925..9b16a32e0 100644 --- a/projects/saturn/src/main/java/io/fairspace/saturn/services/metadata/validation/ValidationException.java +++ b/projects/saturn/src/main/java/io/fairspace/saturn/services/metadata/validation/ValidationException.java @@ -1,6 +1,7 @@ package io.fairspace.saturn.services.metadata.validation; import java.util.Set; +import java.util.stream.Collectors; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -9,4 +10,13 @@ @Getter public class ValidationException extends RuntimeException { private final Set violations; + + @Override + public String getMessage() { + if (violations == null || violations.isEmpty()) { + return "Validation failed with no specific violations."; + } + return "Validation failed with the following violations: " + + violations.stream().map(Violation::toString).collect(Collectors.joining(", ")); + } } From 5e4cee0d9e7bfdb1421da5aef53e6fcc4529a8a3 Mon Sep 17 00:00:00 2001 From: ewelinagr Date: Thu, 2 Jan 2025 09:05:25 +0100 Subject: [PATCH 4/6] Make metadata view name filters case-insensitive. --- .../views/MaterializedViewService.java | 13 ++---- .../services/views/ViewStoreClient.java | 19 +++++---- .../views/ViewStoreClientFactory.java | 7 ++-- .../services/views/JdbcQueryServiceTest.java | 42 +++++++++++++++++++ 4 files changed, 59 insertions(+), 22 deletions(-) diff --git a/projects/saturn/src/main/java/io/fairspace/saturn/services/views/MaterializedViewService.java b/projects/saturn/src/main/java/io/fairspace/saturn/services/views/MaterializedViewService.java index 3eacc95b0..4d44774fa 100644 --- a/projects/saturn/src/main/java/io/fairspace/saturn/services/views/MaterializedViewService.java +++ b/projects/saturn/src/main/java/io/fairspace/saturn/services/views/MaterializedViewService.java @@ -5,7 +5,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Map; import javax.sql.DataSource; import lombok.extern.slf4j.Slf4j; @@ -250,10 +249,8 @@ private void createJoinMaterializedViews( if ("id".equalsIgnoreCase(attr)) { continue; } - var isOfSetType = configuration - .propertyTables - .getOrDefault(joinView.view, Map.of()) - .containsKey(attr); + var propTable = configuration.propertyTables.get(joinView.view); + var isOfSetType = propTable != null && propTable.containsKey(attr); tableAliases.put(joinedTable + "_" + attr.toLowerCase(), isOfSetType ? "jt_" + (i + 1) : "jt_0"); } for (int i = 0; i < joinView.include.size(); i++) { @@ -292,10 +289,8 @@ private void createJoinMaterializedViews( for (int i = 0; i < joinView.include.size(); i++) { var attr = joinView.include.get(i); - var isOfSetType = configuration - .propertyTables - .getOrDefault(joinView.view, Map.of()) - .containsKey(attr); + var propTable = configuration.propertyTables.get(joinView.view); + var isOfSetType = propTable != null && propTable.containsKey(attr); if (!isOfSetType) { continue; } diff --git a/projects/saturn/src/main/java/io/fairspace/saturn/services/views/ViewStoreClient.java b/projects/saturn/src/main/java/io/fairspace/saturn/services/views/ViewStoreClient.java index 112259331..b0668466b 100644 --- a/projects/saturn/src/main/java/io/fairspace/saturn/services/views/ViewStoreClient.java +++ b/projects/saturn/src/main/java/io/fairspace/saturn/services/views/ViewStoreClient.java @@ -10,8 +10,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -23,6 +21,7 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.tuple.Pair; +import org.springframework.util.LinkedCaseInsensitiveMap; import io.fairspace.saturn.config.properties.ViewsProperties; import io.fairspace.saturn.services.views.Table.ColumnDefinition; @@ -34,14 +33,16 @@ public class ViewStoreClient implements AutoCloseable { public static class ViewStoreConfiguration { - final Map viewConfig; - final Map viewTables = new HashMap<>(); - final Map> propertyTables = new HashMap<>(); - final Map> joinTables = new HashMap<>(); + final LinkedCaseInsensitiveMap viewConfig; + final LinkedCaseInsensitiveMap viewTables = new LinkedCaseInsensitiveMap<>(); + final LinkedCaseInsensitiveMap> propertyTables = + new LinkedCaseInsensitiveMap<>(); + final LinkedCaseInsensitiveMap> joinTables = new LinkedCaseInsensitiveMap<>(); public ViewStoreConfiguration(ViewsProperties viewsProperties) { - viewConfig = - viewsProperties.views.stream().collect(Collectors.toMap(view -> view.name, Function.identity())); + viewConfig = new LinkedCaseInsensitiveMap<>(); + viewConfig.putAll( + viewsProperties.views.stream().collect(Collectors.toMap(view -> view.name, Function.identity()))); } } @@ -272,7 +273,7 @@ public void truncateViewTables(String view) throws SQLException { tables.add(configuration.viewTables.get(view)); tables.addAll(configuration .propertyTables - .getOrDefault(view, Collections.emptyMap()) + .getOrDefault(view, new LinkedCaseInsensitiveMap<>()) .values()); var joins = configuration.viewConfig.get(view).join; if (joins != null) { diff --git a/projects/saturn/src/main/java/io/fairspace/saturn/services/views/ViewStoreClientFactory.java b/projects/saturn/src/main/java/io/fairspace/saturn/services/views/ViewStoreClientFactory.java index ace6e6332..7c9d2ca97 100644 --- a/projects/saturn/src/main/java/io/fairspace/saturn/services/views/ViewStoreClientFactory.java +++ b/projects/saturn/src/main/java/io/fairspace/saturn/services/views/ViewStoreClientFactory.java @@ -4,7 +4,6 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -19,6 +18,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; +import org.springframework.util.LinkedCaseInsensitiveMap; import io.fairspace.saturn.config.properties.ViewDatabaseProperties; import io.fairspace.saturn.config.properties.ViewsProperties; @@ -252,7 +252,7 @@ void createOrUpdateView(ViewsProperties.View view) throws SQLException { var name = String.format("%s_%s", view.name.toLowerCase(), column.name.toLowerCase()); var propertyTable = new Table(name, propertyTableColumns); createOrUpdateTable(propertyTable); - configuration.propertyTables.putIfAbsent(view.name, new HashMap<>()); + configuration.propertyTables.putIfAbsent(view.name, new LinkedCaseInsensitiveMap<>()); configuration.propertyTables.get(view.name).put(column.name, propertyTable); } if (view.join != null) { @@ -260,9 +260,8 @@ void createOrUpdateView(ViewsProperties.View view) throws SQLException { for (ViewsProperties.View.JoinView join : view.join) { var joinTable = getJoinTable(join, view); createOrUpdateJoinTable(joinTable); - configuration.joinTables.putIfAbsent(view.name, new HashMap<>()); + configuration.joinTables.putIfAbsent(view.name, new LinkedCaseInsensitiveMap<>()); configuration.joinTables.get(view.name).put(join.view, joinTable); - var joinView = configuration.viewConfig.get(join.view); } } } diff --git a/projects/saturn/src/test/java/io/fairspace/saturn/services/views/JdbcQueryServiceTest.java b/projects/saturn/src/test/java/io/fairspace/saturn/services/views/JdbcQueryServiceTest.java index 4ab572640..3ba60ffb4 100644 --- a/projects/saturn/src/test/java/io/fairspace/saturn/services/views/JdbcQueryServiceTest.java +++ b/projects/saturn/src/test/java/io/fairspace/saturn/services/views/JdbcQueryServiceTest.java @@ -253,6 +253,16 @@ public void testRetrieveSamplePage() { 0.01); } + @Test + public void retrieveSamplePageIsCaseInsensitive() { + var request = new ViewRequest(); + request.setView("sample"); + request.setPage(1); + request.setSize(10); + var page = sut.retrieveViewPage(request); + Assert.assertEquals(2, page.getRows().size()); + } + @Test public void testRetrieveSamplePageAfterReindexing() { maintenanceService.recreateIndex(); @@ -356,6 +366,29 @@ public void testRetrieveSamplePageIncludeJoin() { row2.get("Resource_analysisType").stream().map(ValueDto::label).collect(Collectors.toSet())); } + @Test + public void retrieveSamplePageIncludeJoinIsCaseInsensitive() { + var request = new ViewRequest(); + request.setView("sample"); + request.setPage(1); + request.setSize(10); + request.setIncludeJoinedViews(true); + var page = sut.retrieveViewPage(request); + Assert.assertEquals(2, page.getRows().size()); + var row1 = page.getRows().getFirst(); + Assert.assertEquals( + "Sample A for subject 1", + row1.get("Sample").stream().findFirst().orElseThrow().label()); + Assert.assertEquals(1, row1.get("Subject").size()); + var row2 = page.getRows().get(1); + Assert.assertEquals( + "Sample B for subject 2", + row2.get("Sample").stream().findFirst().orElseThrow().label()); + Assert.assertEquals( + Set.of("RNA-seq", "Whole genome sequencing"), + row2.get("Resource_analysisType").stream().map(ValueDto::label).collect(Collectors.toSet())); + } + @Test public void testRetrieveSamplePageIncludeJoinAfterReindexing() { maintenanceService.recreateIndex(); @@ -389,6 +422,15 @@ public void testCountSamplesWithoutMaxDisplayCount() { assertEquals(2, result.count()); } + @Test + public void countSamplesIsCaseInsensitive() { + selectRegularUser(); + var requestParams = new CountRequest(); + requestParams.setView("sample"); + var result = sut.count(requestParams); + assertEquals(2, result.count()); + } + @Test public void testCountSubjectWithMaxDisplayCountLimitLessThanTotalCount() { var request = new CountRequest(); From 72123811951a6bfbdd9d18b94911c40a2e99c4a4 Mon Sep 17 00:00:00 2001 From: ewelinagr Date: Thu, 2 Jan 2025 09:06:58 +0100 Subject: [PATCH 5/6] Make external link openable in separate tab by default. --- .../mercury/src/metadata/common/values/ReferringValue.js | 4 +++- .../src/metadata/common/values/__tests__/ReferringValue.js | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/projects/mercury/src/metadata/common/values/ReferringValue.js b/projects/mercury/src/metadata/common/values/ReferringValue.js index 7f2719a45..f1893c82a 100644 --- a/projects/mercury/src/metadata/common/values/ReferringValue.js +++ b/projects/mercury/src/metadata/common/values/ReferringValue.js @@ -34,7 +34,9 @@ export const ReferringValue = ({property, entry}) => { // External links should be represented by a direct link to the URI itself // Other iri entities should be opened in the metadata editor return property.isExternalLink ? ( - {entry.id} + + {entry.id} + ) : ( {displayValue} ); diff --git a/projects/mercury/src/metadata/common/values/__tests__/ReferringValue.js b/projects/mercury/src/metadata/common/values/__tests__/ReferringValue.js index 29d4c7586..784e7add7 100644 --- a/projects/mercury/src/metadata/common/values/__tests__/ReferringValue.js +++ b/projects/mercury/src/metadata/common/values/__tests__/ReferringValue.js @@ -18,7 +18,11 @@ describe('ReferringValue', () => { property, entry }) - ).toEqual(https://thehyve.nl); + ).toEqual( + + https://thehyve.nl + + ); }); it('should render a generic iri resource as link to editor', () => { From 3ced2b8f06bff06cc154018f9d5b96b4cc44e194 Mon Sep 17 00:00:00 2001 From: ewelinagr Date: Thu, 2 Jan 2025 09:22:53 +0100 Subject: [PATCH 6/6] Add copy filters and resolvable URL query params feature. --- projects/mercury/src/constants.js | 2 + .../src/metadata/views/MetadataView.js | 91 +++++++++++++++---- .../src/metadata/views/MetadataView.styles.js | 6 +- .../views/MetadataViewActiveFacetFilters.js | 4 +- .../src/metadata/views/MetadataViewContext.js | 8 +- .../src/metadata/views/MetadataViewFacets.js | 4 +- .../src/metadata/views/MetadataViewTable.js | 23 +---- 7 files changed, 94 insertions(+), 44 deletions(-) diff --git a/projects/mercury/src/constants.js b/projects/mercury/src/constants.js index b0cbada34..4d2b9e43e 100644 --- a/projects/mercury/src/constants.js +++ b/projects/mercury/src/constants.js @@ -22,6 +22,8 @@ export const DATE_FORMAT = 'dd-MM-yyyy'; // The maximum number of items in a list in the right panel, for performance reasons. // If you change this, also change it in 'MetadataService.java' export const MAX_LIST_LENGTH = 100; +// Max length of URL in the browser +export const MAX_URL_LENGTH = 2000; // Metadata schemas export const SHACL_NS = 'http://www.w3.org/ns/shacl#'; diff --git a/projects/mercury/src/metadata/views/MetadataView.js b/projects/mercury/src/metadata/views/MetadataView.js index 5bf908525..da519ad0e 100644 --- a/projects/mercury/src/metadata/views/MetadataView.js +++ b/projects/mercury/src/metadata/views/MetadataView.js @@ -3,9 +3,11 @@ import _ from 'lodash'; import {useHistory} from 'react-router-dom'; import {Button, Grid, Typography} from '@mui/material'; import withStyles from '@mui/styles/withStyles'; -import {Assignment, Close} from '@mui/icons-material'; +import {Assignment, Close, ContentCopy} from '@mui/icons-material'; import queryString from 'query-string'; +import qs from 'qs'; +import {SnackbarProvider, useSnackbar} from 'notistack'; import styles from './MetadataView.styles'; import type {MetadataViewFacet, MetadataViewFilter, MetadataViewOptions, ValueType} from './MetadataViewAPI'; import BreadCrumbs from '../../common/components/BreadCrumbs'; @@ -34,6 +36,7 @@ import usePageTitleUpdater from '../../common/hooks/UsePageTitleUpdater'; import MetadataViewFacetsContext from './MetadataViewFacetsContext'; import {accessLevelForCollection} from '../../collections/collectionUtils'; import InternalMetadataSourceContext from '../metadata-sources/InternalMetadataSourceContext'; +import {MAX_URL_LENGTH} from '../../constants'; type ContextualMetadataViewProperties = { classes: any @@ -70,6 +73,7 @@ export const MetadataView = (props: MetadataViewProperties) => { const {collections} = useContext(CollectionsContext); const {toggle, selected} = useSingleSelection(); + const {enqueueSnackbar} = useSnackbar(); const [filterCandidates, setFilterCandidates] = useState([]); const [textFiltersObject, setTextFiltersObject] = useState({}); @@ -199,7 +203,9 @@ export const MetadataView = (props: MetadataViewProperties) => { }; const areFacetFiltersNonEmpty = useMemo( - () => filters && filters.some(filter => facetsEx.some(facet => facet.name === filter.field)), + () => + filters && + filters.some(filter => facetsEx.some(facet => facet.name.toLowerCase() === filter.field.toLowerCase())), [filters, facetsEx] ); const areTextFiltersNonEmpty = useMemo( @@ -218,6 +224,48 @@ export const MetadataView = (props: MetadataViewProperties) => { return `${window.location.host}${pathPrefix}?${prefilteringQueryString}`; }; + const copyFiltersUrl = () => { + const queryParams = filters.reduce((acc, filter) => { + acc[filter.field.toLowerCase()] = filter.values.join(','); + return acc; + }, {}); + const queryStringFilters = queryString.stringify(queryParams); + const url = `${window.location.protocol}//${window.location.host}/metadata-views?view=${currentView.name}&${queryStringFilters}`; + + if (url.length > MAX_URL_LENGTH) { + enqueueSnackbar('Failed to copy metadata view filters URL to clipboard: URL too long'); + return; + } + navigator.clipboard + .writeText(url) + .then(() => enqueueSnackbar('Metadata view filters URL copied to clipboard')) + .catch(() => enqueueSnackbar('Failed to copy metadata view filters URL to clipboard')); + }; + + useEffect(() => { + const queryStringFilters = qs.parse(window.location.search, {ignoreQueryPrefix: true}); + if (queryStringFilters && Object.keys(queryStringFilters).length > 0) { + const idTextFilter = queryStringFilters[currentViewIdColumn.name.toLowerCase()]; + if (idTextFilter && (!areTextFiltersNonEmpty || !textFiltersObject.keys.includes(currentViewIdColumn))) { + setTextFiltersObject({...textFiltersObject, [currentViewIdColumn.name]: idTextFilter}); + } + if (!areFacetFiltersNonEmpty) { + const facetNames = facets.map(f => f.name.toLowerCase()); + const newFilters = Object.keys(queryStringFilters) + .filter(k => facetNames.includes(k.toLowerCase())) + .reduce((arr, key) => { + arr.push({ + field: key, + values: queryStringFilters[key].split(',') + }); + return arr; + }, []); + updateFilters(newFilters); + } + } + // eslint-disable-next-line + }, []); + return ( { {(areFacetFiltersNonEmpty || areTextFiltersNonEmpty) && ( - + + @@ -348,19 +399,21 @@ export const ContextualMetadataView = (props: ContextualMetadataViewProperties) }; return ( - + + + ); }; diff --git a/projects/mercury/src/metadata/views/MetadataView.styles.js b/projects/mercury/src/metadata/views/MetadataView.styles.js index 52f96d12a..da55f9c43 100644 --- a/projects/mercury/src/metadata/views/MetadataView.styles.js +++ b/projects/mercury/src/metadata/views/MetadataView.styles.js @@ -29,9 +29,11 @@ const styles = theme => ({ clearAllButtonContainer: { textAlign: 'end' }, - clearAllButton: { + filterButtons: { color: theme.palette.primary.contrastText, - background: theme.palette.primary.main + background: theme.palette.primary.main, + marginLeft: 1, + marginBottom: 1 }, activeFilters: { marginBottom: 10 diff --git a/projects/mercury/src/metadata/views/MetadataViewActiveFacetFilters.js b/projects/mercury/src/metadata/views/MetadataViewActiveFacetFilters.js index fc6d8632a..8343f9014 100644 --- a/projects/mercury/src/metadata/views/MetadataViewActiveFacetFilters.js +++ b/projects/mercury/src/metadata/views/MetadataViewActiveFacetFilters.js @@ -64,7 +64,7 @@ export const MetadataViewActiveFacetFilters = (props: MetadataViewActiveFacetFil ); } return filter.values.map(valueIri => { - const value = facet.values.find(val => val.value === valueIri); + const value = facet.values.find(val => val.value.toLowerCase() === valueIri.toLowerCase()); return ( value && ( f.name === filter.field); + const facet = facets.find(f => f.name.toLowerCase() === filter.field.toLowerCase()); if (facet) { return ( diff --git a/projects/mercury/src/metadata/views/MetadataViewContext.js b/projects/mercury/src/metadata/views/MetadataViewContext.js index 7a366df34..d10470f41 100644 --- a/projects/mercury/src/metadata/views/MetadataViewContext.js +++ b/projects/mercury/src/metadata/views/MetadataViewContext.js @@ -1,4 +1,5 @@ import React from 'react'; +// import {useHistory} from 'react-router-dom'; import type {MetadataViewFilter} from './MetadataViewAPI'; import MetadataViewAPI from './MetadataViewAPI'; import useAsync from '../../common/hooks/UseAsync'; @@ -11,6 +12,7 @@ const SESSION_STORAGE_METADATA_FILTERS_KEY = 'FAIRSPACE_METADATA_FILTERS'; export const MetadataViewProvider = ({children, metadataViewAPI = MetadataViewAPI, sourceName = ''}) => { const {data = {}, error, loading, refresh} = useAsync(() => metadataViewAPI.getViews(), []); + // const history = useHistory(); const [filters: MetadataViewFilter[], setFilters] = useStateWithSessionStorage( `${SESSION_STORAGE_METADATA_FILTERS_KEY}_${sourceName}`, @@ -23,11 +25,15 @@ export const MetadataViewProvider = ({children, metadataViewAPI = MetadataViewAP const clearAllFilters = () => { setFilters([]); + + const queryParams = new URLSearchParams(window.location.search); + const viewParam = queryParams.get('view'); + window.history.replaceState(null, '', `${window.location.pathname}?${viewParam ? `view=${viewParam}` : ''}`); }; const updateFilters = (filterCandidates: MetadataViewFilter[]) => { setFilters([ - ...filters.filter(f => !filterCandidates.some(u => u.field === f.field)), + ...filters.filter(f => !filterCandidates.some(u => u.field.toLowerCase() === f.field.toLowerCase())), ...filterCandidates.filter( f => (f.values && f.values.length > 0) || diff --git a/projects/mercury/src/metadata/views/MetadataViewFacets.js b/projects/mercury/src/metadata/views/MetadataViewFacets.js index d31d08eec..a339309f1 100644 --- a/projects/mercury/src/metadata/views/MetadataViewFacets.js +++ b/projects/mercury/src/metadata/views/MetadataViewFacets.js @@ -79,7 +79,9 @@ export const MetadataViewFacets = (props: MetadataViewFacetsProperties) => { const renderSingleFacet = (facet: MetadataViewFacet) => { const facetOptions = getFilterValues(facet.type, facet); - const activeFilter = [...filterCandidates, ...filters].find(filter => filter.field === facet.name); + const activeFilter = [...filterCandidates, ...filters].find( + filter => filter.field.toLowerCase() === facet.name.toLowerCase() + ); let activeFilterValues = []; if (activeFilter) { activeFilterValues = getFilterValues(facet.type, activeFilter); diff --git a/projects/mercury/src/metadata/views/MetadataViewTable.js b/projects/mercury/src/metadata/views/MetadataViewTable.js index 3472b5074..66f557640 100644 --- a/projects/mercury/src/metadata/views/MetadataViewTable.js +++ b/projects/mercury/src/metadata/views/MetadataViewTable.js @@ -1,15 +1,14 @@ -import React, {useCallback, useEffect} from 'react'; +import React, {useCallback} from 'react'; import {Checkbox, Link, Table, TableBody, TableCell, TableHead, TableRow} from '@mui/material'; import {Check, Close} from '@mui/icons-material'; import makeStyles from '@mui/styles/makeStyles'; import {Link as RouterLink} from 'react-router-dom'; -import qs from 'qs'; import useDeepCompareEffect from 'use-deep-compare-effect'; import type {MetadataViewColumn, MetadataViewData} from './MetadataViewAPI'; import {TextualValueTypes} from './MetadataViewAPI'; import type {MetadataViewEntity, MetadataViewEntityWithLinkedFiles} from './metadataViewUtils'; import {RESOURCES_VIEW} from './metadataViewUtils'; -import {stringToBooleanValueOrNull, formatDate} from '../../common/utils/genericUtils'; +import {formatDate, stringToBooleanValueOrNull} from '../../common/utils/genericUtils'; import type {Collection} from '../../collections/CollectionAPI'; import {collectionAccessIcon} from '../../collections/collectionUtils'; import {getPathFromIri, redirectLink} from '../../file/fileUtils'; @@ -52,12 +51,12 @@ const RESOURCE_TYPE_COLUMN = `${RESOURCES_VIEW}_type`; export const MetadataViewTable = (props: MetadataViewTableProperties) => { const {columns, visibleColumnNames, loading, data, toggleRow, selected, view, idColumn, history, collections} = props; - const classes = useStyles(); const {textFiltersObject, setTextFiltersObject} = props; + const {checkboxes, setCheckboxState} = props; + const classes = useStyles(); const visibleColumns = columns.filter(column => visibleColumnNames.includes(column.name)); const dataLinkColumn = columns.find(c => c.type === 'dataLink'); const isResourcesView = view === RESOURCES_VIEW; - const {checkboxes, setCheckboxState} = props; const isCustomResourceColumn = (column: MetadataViewColumn) => isResourcesView && CUSTOM_RESOURCE_COLUMNS.includes(column.name) && column.type === 'Custom'; @@ -67,11 +66,6 @@ export const MetadataViewTable = (props: MetadataViewTableProperties) => { return col ? col.access : 'None'; }; - const getIdColumnFilterFromSearchParams = () => { - const idColumnName = idColumn.name.toLowerCase(); - return qs.parse(window.location.search, {ignoreQueryPrefix: true})[idColumnName]; - }; - const getResourceType = (row: Map) => row[RESOURCE_TYPE_COLUMN] && row[RESOURCE_TYPE_COLUMN][0] && row[RESOURCE_TYPE_COLUMN][0].value; @@ -82,15 +76,6 @@ export const MetadataViewTable = (props: MetadataViewTableProperties) => { toggleRow({label, iri, linkedFiles: linkedFiles || []}); } }; - useEffect(() => { - if (!textFiltersObject || !textFiltersObject.keys || !textFiltersObject.keys.includes(idColumn)) { - const idColumnTextFilter = getIdColumnFilterFromSearchParams(); - if (idColumnTextFilter) { - setTextFiltersObject({...textFiltersObject, [idColumn.name]: idColumnTextFilter}); - } - } - // eslint-disable-next-line - }, []); const initializeCheckboxes = useCallback(() => { if (idColumn && data && data.rows) {