From 8f7e9db9b264328ce8653ee60a5fb3e33db28961 Mon Sep 17 00:00:00 2001 From: Bill Dueber Date: Mon, 11 May 2026 12:24:21 -0400 Subject: [PATCH 1/4] feat: update field names to new schema and add group/type/HLB facets - Rename all abbreviated dc_* field names (dc_ti, dc_cr, etc.) to full Dublin Core names (dc_title, dc_creator, etc.) for dor-dc-20260509 index - Change .keyword subfields to .facet on all MultiList dataField props - Remove legacy xx_dc_* and XXX_dc_* field display blocks (dropped in new index) - Remove duplicate dc_ty display block (merged into dc_type) - Add three new MultiList facets: group (groupName.facet), type (collection_type.facet), and HLB (hlb.facet) - Wire all seven facets into each other's react.and arrays and ReactiveList - Add hlb^3 and groupName^2 to best_fields multi_match query - Update feedback form to report new filter values --- src/apps/RsDorDcApp/index.jsx | 268 +++++++++++++++++++--------------- 1 file changed, 151 insertions(+), 117 deletions(-) diff --git a/src/apps/RsDorDcApp/index.jsx b/src/apps/RsDorDcApp/index.jsx index 481d0ba..7db3a47 100644 --- a/src/apps/RsDorDcApp/index.jsx +++ b/src/apps/RsDorDcApp/index.jsx @@ -52,7 +52,10 @@ function RsDorDcApp() { collection: [], subject: [], date: [], - coverage: [] + coverage: [], + group: [], + type: [], + HLB: [], }); const latestDataRef = useRef([]); const searchQueryRef = useRef(''); @@ -121,6 +124,15 @@ function RsDorDcApp() { if (filters.coverage.length > 0) { filterParts.push(`Coverage: ${filters.coverage.join(', ')}`); } + if (filters.group.length > 0) { + filterParts.push(`Group: ${filters.group.join(', ')}`); + } + if (filters.type.length > 0) { + filterParts.push(`Type: ${filters.type.join(', ')}`); + } + if (filters.HLB.length > 0) { + filterParts.push(`Subject Area: ${filters.HLB.join(', ')}`); + } if (filterParts.length > 0) { if (fullQuery) { @@ -138,10 +150,10 @@ function RsDorDcApp() { const resultsData = latestDataRef.current; if (resultsData && resultsData.length > 0) { const top5Results = resultsData.slice(0, 5).map((item, index) => { - // Handle dc_ti as either string or array + // Handle dc_title as either string or array let title = 'Untitled'; - if (item.dc_ti) { - const titleRaw = Array.isArray(item.dc_ti) ? item.dc_ti.join(', ') : item.dc_ti; + if (item.dc_title) { + const titleRaw = Array.isArray(item.dc_title) ? item.dc_title.join(', ') : item.dc_title; title = titleRaw.replace(/<[^>]*>/g, ''); } return `${index + 1}. ${title}`; @@ -170,6 +182,18 @@ function RsDorDcApp() { setFilters(prev => ({ ...prev, coverage: value || [] })); }, []); + const handleGroupChange = useCallback((value) => { + setFilters(prev => ({ ...prev, group: value || [] })); + }, []); + + const handleTypeChange = useCallback((value) => { + setFilters(prev => ({ ...prev, type: value || [] })); + }, []); + + const handleHLBChange = useCallback((value) => { + setFilters(prev => ({ ...prev, HLB: value || [] })); + }, []); + const handleSearchChange = useCallback(async (value) => { // Store raw query in ref searchQueryRef.current = value || ''; @@ -206,7 +230,10 @@ function RsDorDcApp() { collection: [], subject: [], date: [], - coverage: [] + coverage: [], + group: [], + type: [], + HLB: [], }); }, []); @@ -248,7 +275,7 @@ function RsDorDcApp() { @@ -264,7 +291,7 @@ function RsDorDcApp() { @@ -280,7 +307,7 @@ function RsDorDcApp() { @@ -296,7 +323,7 @@ function RsDorDcApp() { + + + + + + + + + { // Store latest data in ref for feedback form @@ -439,12 +515,12 @@ function RsDorDcApp() { {data.map((item) => ( - - -
- {item.dc_cr && ( -
)} + + +
+ {item.dc_creator && ( +
)} {item.collection_id && item.item_id && item.media_id && item.media_id !== "NOFILE" && (
- {item.XXX_dc_de && ( + {item.dc_contributor && ( <> -
XXX_dc_de:
-
{Array.isArray(item.XXX_dc_de) ? item.XXX_dc_de.join(', ') : item.XXX_dc_de}
+
dc_contributor:
+
{Array.isArray(item.dc_contributor) ? item.dc_contributor.join(', ') : item.dc_contributor}
)} - {item.dc_co && ( + {item.dc_coverage && ( <> -
dc_co:
-
{Array.isArray(item.dc_co) ? item.dc_co.join(', ') : item.dc_co}
+
dc_coverage:
+
{Array.isArray(item.dc_coverage) ? item.dc_coverage.join(', ') : item.dc_coverage}
)} - {item.dc_cov && ( + {item.dc_creator && ( <> -
dc_cov:
-
{Array.isArray(item.dc_cov) ? item.dc_cov.join(', ') : item.dc_cov}
+
dc_creator:
+
{Array.isArray(item.dc_creator) ? item.dc_creator.join(', ') : item.dc_creator}
)} - {item.dc_cr && ( + {item.dc_date && ( <> -
dc_cr:
-
{Array.isArray(item.dc_cr) ? item.dc_cr.join(', ') : item.dc_cr}
+
dc_date:
+
{Array.isArray(item.dc_date) ? item.dc_date.join(', ') : item.dc_date}
)} - {item.dc_da && ( + {item.dc_description && ( <> -
dc_da:
-
{Array.isArray(item.dc_da) ? item.dc_da.join(', ') : item.dc_da}
+
dc_description:
+
{Array.isArray(item.dc_description) ? item.dc_description.join(', ') : item.dc_description}
)} - {item.dc_de && ( + {item.dc_format && ( <> -
dc_de:
-
{Array.isArray(item.dc_de) ? item.dc_de.join(', ') : item.dc_de}
+
dc_format:
+
{Array.isArray(item.dc_format) ? item.dc_format.join(', ') : item.dc_format}
)} - {item.dc_fo && ( + {item.dc_genre && ( <> -
dc_fo:
-
{Array.isArray(item.dc_fo) ? item.dc_fo.join(', ') : item.dc_fo}
+
dc_genre:
+
{Array.isArray(item.dc_genre) ? item.dc_genre.join(', ') : item.dc_genre}
)} - {item.dc_ge && ( + {item.dc_language && ( <> -
dc_ge:
-
{Array.isArray(item.dc_ge) ? item.dc_ge.join(', ') : item.dc_ge}
+
dc_language:
+
{Array.isArray(item.dc_language) ? item.dc_language.join(', ') : item.dc_language}
)} - {item.dc_la && ( + {item.dc_location && ( <> -
dc_la:
-
{Array.isArray(item.dc_la) ? item.dc_la.join(', ') : item.dc_la}
+
dc_location:
+
{Array.isArray(item.dc_location) ? item.dc_location.join(', ') : item.dc_location}
)} - {item.dc_lo && ( + {item.dc_publisher && ( <> -
dc_lo:
-
{Array.isArray(item.dc_lo) ? item.dc_lo.join(', ') : item.dc_lo}
+
dc_publisher:
+
{Array.isArray(item.dc_publisher) ? item.dc_publisher.join(', ') : item.dc_publisher}
)} - {item.dc_pu && ( + {item.dc_rights && ( <> -
dc_pu:
-
{Array.isArray(item.dc_pu) ? item.dc_pu.join(', ') : item.dc_pu}
+
dc_rights:
+
{Array.isArray(item.dc_rights) ? item.dc_rights.join(', ') : item.dc_rights}
)} - {item.dc_re && ( + {item.dc_relation && ( <> -
dc_re:
-
{Array.isArray(item.dc_re) ? item.dc_re.join(', ') : item.dc_re}
+
dc_relation:
+
{Array.isArray(item.dc_relation) ? item.dc_relation.join(', ') : item.dc_relation}
)} - {item.dc_rel && ( + {item.dc_source && ( <> -
dc_rel:
-
{Array.isArray(item.dc_rel) ? item.dc_rel.join(', ') : item.dc_rel}
+
dc_source:
+
{Array.isArray(item.dc_source) ? item.dc_source.join(', ') : item.dc_source}
)} - {item.dc_so && ( + {item.dc_subject && ( <> -
dc_so:
-
{Array.isArray(item.dc_so) ? item.dc_so.join(', ') : item.dc_so}
- - )} - {item.dc_su && ( - <> -
dc_su:
-
{Array.isArray(item.dc_su) ? item.dc_su.join(', ') : item.dc_su}
- - )} - {item.dc_ty && ( - <> -
dc_ty:
-
{Array.isArray(item.dc_ty) ? item.dc_ty.join(', ') : item.dc_ty}
+
dc_subject:
+
{Array.isArray(item.dc_subject) ? item.dc_subject.join(', ') : item.dc_subject}
)} {item.dc_type && ( @@ -572,36 +636,6 @@ function RsDorDcApp() {
{Array.isArray(item.dc_type) ? item.dc_type.join(', ') : item.dc_type}
)} - {item.xx_dc_co && ( - <> -
xx_dc_co:
-
{Array.isArray(item.xx_dc_co) ? item.xx_dc_co.join(', ') : item.xx_dc_co}
- - )} - {item.xx_dc_cr && ( - <> -
xx_dc_cr:
-
{Array.isArray(item.xx_dc_cr) ? item.xx_dc_cr.join(', ') : item.xx_dc_cr}
- - )} - {item.xx_dc_cv && ( - <> -
xx_dc_cv:
-
{Array.isArray(item.xx_dc_cv) ? item.xx_dc_cv.join(', ') : item.xx_dc_cv}
- - )} - {item.xx_dc_fo && ( - <> -
xx_dc_fo:
-
{Array.isArray(item.xx_dc_fo) ? item.xx_dc_fo.join(', ') : item.xx_dc_fo}
- - )} - {item.xx_dc_so && ( - <> -
xx_dc_so:
-
{Array.isArray(item.xx_dc_so) ? item.xx_dc_so.join(', ') : item.xx_dc_so}
- - )}
From 8a58ddc4662c912eaf046eee9c8f23975985247d Mon Sep 17 00:00:00 2001 From: Greg Kostin Date: Mon, 11 May 2026 14:21:21 -0400 Subject: [PATCH 2/4] some changes --- src/apps/RsDorDcApp/index.jsx | 52 +++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/apps/RsDorDcApp/index.jsx b/src/apps/RsDorDcApp/index.jsx index 7db3a47..9d38107 100644 --- a/src/apps/RsDorDcApp/index.jsx +++ b/src/apps/RsDorDcApp/index.jsx @@ -261,7 +261,7 @@ function RsDorDcApp() { /> )} @@ -299,9 +299,9 @@ function RsDorDcApp() { placeholder="Search subjects" value={filters.subject} react={{ - and: ["search", "collection", "coverage", "date", "group", "type", "HLB"] + and: ["search", "collection", "subject", "coverage", "date", "group", "type", "HLB"] }} - onValueChange={handleSubjectChange} + onChange={handleSubjectChange} /> @@ -315,9 +315,9 @@ function RsDorDcApp() { placeholder="Search dates" value={filters.date} react={{ - and: ["search", "collection", "subject", "coverage", "group", "type", "HLB"] + and: ["search", "collection", "subject", "coverage", "date", "group", "type", "HLB"] }} - onValueChange={handleDateChange} + onChange={handleDateChange} /> @@ -331,9 +331,9 @@ function RsDorDcApp() { placeholder="Search coverage" value={filters.coverage} react={{ - and: ["search", "collection", "subject", "date", "group", "type", "HLB"] + and: ["search", "collection", "subject", "coverage", "date", "group", "type", "HLB"] }} - onValueChange={handleCoverageChange} + onChange={handleCoverageChange} /> @@ -347,9 +347,9 @@ function RsDorDcApp() { placeholder="Search groups" value={filters.group} react={{ - and: ["search", "collection", "subject", "date", "coverage", "type", "HLB"] + and: ["search", "collection", "subject", "date", "group", "coverage", "type", "HLB"] }} - onValueChange={handleGroupChange} + onChange={handleGroupChange} /> @@ -362,9 +362,9 @@ function RsDorDcApp() { showSearch={false} value={filters.type} react={{ - and: ["search", "collection", "subject", "date", "coverage", "group", "HLB"] + and: ["search", "collection", "subject", "date", "coverage", "group", "type", "HLB"] }} - onValueChange={handleTypeChange} + onChange={handleTypeChange} /> @@ -378,21 +378,21 @@ function RsDorDcApp() { placeholder="Search subject areas" value={filters.HLB} react={{ - and: ["search", "collection", "subject", "date", "coverage", "group", "type"] + and: ["search", "collection", "subject", "date", "coverage", "group", "type", "HLB"] }} - onValueChange={handleHLBChange} + onChange={handleHLBChange} /> { if (!value) return null; @@ -546,6 +546,24 @@ function RsDorDcApp() { gap: '8px 16px', alignItems: 'start' }}> + {item.collection_name && ( + <> +
collection_name:
+
{Array.isArray(item.collection_name) ? item.collection_name.join(', ') : item.collection_name}
+ + )} + {item.hlb && ( + <> +
hlb:
+
{Array.isArray(item.hlb) ? item.hlb.join(', ') : item.hlb}
+ + )} + {item.groupName && ( + <> +
groupName:
+
{Array.isArray(item.groupName) ? item.groupName.join(', ') : item.groupName}
+ + )} {item.dc_contributor && ( <>
dc_contributor:
From 475cd8d8433cc8cc2476a3a410661ad753459cc8 Mon Sep 17 00:00:00 2001 From: Greg Kostin Date: Mon, 11 May 2026 14:54:31 -0400 Subject: [PATCH 3/4] Clear all filters fix --- src/apps/RsDorDcApp/index.jsx | 42 +++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/apps/RsDorDcApp/index.jsx b/src/apps/RsDorDcApp/index.jsx index 9d38107..0d989b5 100644 --- a/src/apps/RsDorDcApp/index.jsx +++ b/src/apps/RsDorDcApp/index.jsx @@ -7,6 +7,7 @@ import { ResultList, SearchBox, SelectedFilters, + StateProvider, } from '@appbaseio/reactivesearch'; // console.log(Object.keys(ReactiveSearch)); @@ -60,6 +61,7 @@ function RsDorDcApp() { const latestDataRef = useRef([]); const searchQueryRef = useRef(''); const parsedQueryRef = useRef(''); + const setSearchStateRef = useRef(null); useEffect(() => { // Test connections to ReactiveSearch and Search Parser @@ -235,6 +237,9 @@ function RsDorDcApp() { type: [], HLB: [], }); + if (setSearchStateRef.current) { + setSearchStateRef.current({}); + } }, []); return ( @@ -270,6 +275,12 @@ function RsDorDcApp() { enableQueryRules: false, }} > + { + setSearchStateRef.current = setSearchState; + return null; + }} + /> @@ -281,11 +292,10 @@ function RsDorDcApp() { sortBy="count" showSearch={true} placeholder="Search collections" - value={filters.collection} react={{ - and: ["search", "collection", "subject", "coverage", "date", "group", "type", "HLB"] + and: ["search", "collection", "subject", "date", "coverage", "group", "type", "HLB"] }} - onChange={handleCollectionChange} + onValueChange={handleCollectionChange} /> @@ -297,11 +307,10 @@ function RsDorDcApp() { sortBy="count" showSearch={true} placeholder="Search subjects" - value={filters.subject} react={{ - and: ["search", "collection", "subject", "coverage", "date", "group", "type", "HLB"] + and: ["search", "collection", "subject", "date", "coverage", "group", "type", "HLB"] }} - onChange={handleSubjectChange} + onValueChange={handleSubjectChange} /> @@ -313,11 +322,10 @@ function RsDorDcApp() { sortBy="count" showSearch={true} placeholder="Search dates" - value={filters.date} react={{ - and: ["search", "collection", "subject", "coverage", "date", "group", "type", "HLB"] + and: ["search", "collection", "subject", "date", "coverage", "group", "type", "HLB"] }} - onChange={handleDateChange} + onValueChange={handleDateChange} /> @@ -329,11 +337,10 @@ function RsDorDcApp() { sortBy="count" showSearch={true} placeholder="Search coverage" - value={filters.coverage} react={{ - and: ["search", "collection", "subject", "coverage", "date", "group", "type", "HLB"] + and: ["search", "collection", "subject", "date", "coverage", "group", "type", "HLB"] }} - onChange={handleCoverageChange} + onValueChange={handleCoverageChange} /> @@ -345,11 +352,10 @@ function RsDorDcApp() { sortBy="count" showSearch={true} placeholder="Search groups" - value={filters.group} react={{ - and: ["search", "collection", "subject", "date", "group", "coverage", "type", "HLB"] + and: ["search", "collection", "subject", "date", "coverage", "group", "type", "HLB"] }} - onChange={handleGroupChange} + onValueChange={handleGroupChange} /> @@ -360,11 +366,10 @@ function RsDorDcApp() { aggregationSize={2000} sortBy="count" showSearch={false} - value={filters.type} react={{ and: ["search", "collection", "subject", "date", "coverage", "group", "type", "HLB"] }} - onChange={handleTypeChange} + onValueChange={handleTypeChange} /> @@ -376,11 +381,10 @@ function RsDorDcApp() { sortBy="count" showSearch={true} placeholder="Search subject areas" - value={filters.HLB} react={{ and: ["search", "collection", "subject", "date", "coverage", "group", "type", "HLB"] }} - onChange={handleHLBChange} + onValueChange={handleHLBChange} /> From dbee422417e7f60594de4f2c70b39cb61eaca49b Mon Sep 17 00:00:00 2001 From: Greg Kostin Date: Tue, 12 May 2026 11:01:06 -0400 Subject: [PATCH 4/4] fix: clean up lint and update env template for new OpenSearch URL - eslint.config.js: exclude mlibrary_search_parser/ and search-parser-service/ from linting (vendored/external code) - vite.config.js: remove unused `mode` parameter - OsDorDcApp/index.jsx: suppress no-unused-vars for commented-out price range state setters (intentionally kept for future use) - OsDorDcApp/services/openSearchService.js: suppress no-unused-vars for priceRange parameter (intentionally kept for future use) - env.template.sh: update VITE_OPENSEARCH_URL to opensearch.discovery.dor.lib.umich.edu (hos. host is retired) npm run lint now passes cleanly with 0 errors. --- env.template.sh | 4 ++-- eslint.config.js | 2 +- src/apps/OsDorDcApp/index.jsx | 7 ++++++- src/apps/OsDorDcApp/services/openSearchService.js | 1 + vite.config.js | 2 +- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/env.template.sh b/env.template.sh index ab05de7..c740641 100644 --- a/env.template.sh +++ b/env.template.sh @@ -1,5 +1,5 @@ -VITE_OPENSEARCH_URL="http://opensearch:9200" -VITE_OPENSEARCH_CREDENTIALS="admin:password" +VITE_OPENSEARCH_URL="https://opensearch.discovery.dor.lib.umich.edu" +VITE_OPENSEARCH_CREDENTIALS="admin:CHANGEME" VITE_REACTIVESEARCH_URL="http://reactivesearch:8000" VITE_REACTIVESEARCH_CREDENTIALS="admin:password" VITE_SEARCH_PARSER_URL="http://search-parser:4567" diff --git a/eslint.config.js b/eslint.config.js index cee1e2c..fd8a3d3 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -5,7 +5,7 @@ import reactRefresh from 'eslint-plugin-react-refresh' import { defineConfig, globalIgnores } from 'eslint/config' export default defineConfig([ - globalIgnores(['dist']), + globalIgnores(['dist', 'mlibrary_search_parser/**', 'search-parser-service/**']), { files: ['**/*.{js,jsx}'], extends: [ diff --git a/src/apps/OsDorDcApp/index.jsx b/src/apps/OsDorDcApp/index.jsx index 626df66..51bf020 100644 --- a/src/apps/OsDorDcApp/index.jsx +++ b/src/apps/OsDorDcApp/index.jsx @@ -19,9 +19,13 @@ function OsDorDcApp() { const [loading, setLoading] = useState(false); const [searchQuery, setSearchQuery] = useState(""); const [collectionFilter, setCollectionFilter] = useState(COLLECTION_OPTIONS.ALL); + // eslint-disable-next-line no-unused-vars const [minPrice, setMinPrice] = useState(PRICE_RANGE.DEFAULT_MIN); + // eslint-disable-next-line no-unused-vars const [maxPrice, setMaxPrice] = useState(PRICE_RANGE.DEFAULT_MAX); + // eslint-disable-next-line no-unused-vars const [actualMinPrice, setActualMinPrice] = useState(PRICE_RANGE.DEFAULT_MIN); + // eslint-disable-next-line no-unused-vars const [actualMaxPrice, setActualMaxPrice] = useState(PRICE_RANGE.DEFAULT_MAX); const [error, setError] = useState(null); const [connectionStatus, setConnectionStatus] = useState('checking'); @@ -86,7 +90,8 @@ function OsDorDcApp() { if (actualMaxPrice > 0) { fetchThings("", COLLECTION_OPTIONS.ALL, {min: actualMinPrice, max: actualMaxPrice}); } - }, [actualMaxPrice]); // Fetch things once we have price stats + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [actualMaxPrice]); // Fetch things once we have price stats (actualMinPrice intentionally omitted) const handleSearch = () => { fetchThings(searchQuery, collectionFilter, {min: minPrice, max: maxPrice}); diff --git a/src/apps/OsDorDcApp/services/openSearchService.js b/src/apps/OsDorDcApp/services/openSearchService.js index b3f2441..d946390 100644 --- a/src/apps/OsDorDcApp/services/openSearchService.js +++ b/src/apps/OsDorDcApp/services/openSearchService.js @@ -120,6 +120,7 @@ export const getCollections = async () => { // }; // }; +// eslint-disable-next-line no-unused-vars export const searchThings = async (query, collection, priceRange = null, size = 50) => { // Build the base query let queryObj; diff --git a/vite.config.js b/vite.config.js index bc84e99..2b434b3 100644 --- a/vite.config.js +++ b/vite.config.js @@ -2,7 +2,7 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' // https://vite.dev/config/ -export default defineConfig(({ mode }) => { +export default defineConfig(() => { return { plugins: [react()], server: {