Skip to content

Comments

Enhance search experience with repository filtering and sidebar UI refactor#564

Merged
jrhoads merged 24 commits intomasterfrom
funded-ui
Feb 9, 2026
Merged

Enhance search experience with repository filtering and sidebar UI refactor#564
jrhoads merged 24 commits intomasterfrom
funded-ui

Conversation

@jrhoads
Copy link
Contributor

@jrhoads jrhoads commented Feb 5, 2026

closes: https://github.com/datacite/product-backlog/issues/516
closes: https://github.com/datacite/product-backlog/issues/517

Purpose

This PR introduces filtering improvements to the search experience across DOI, ORCID, ROR, and Repository pages. It specifically adds repository-based filtering and enhances the user interface with better spacing, consistent search box placement, and informative tooltips for connection types.

Approach

The changes reorganize the layout of the search pages to place the search box in the sidebar consistently. It also introduces a new clients facet (Repository) and reusable tooltip components for organization relation types.

Key Modifications

  • Search UI Refactor: Moved SearchBox to the sidebar across doi.org, repositories, and ror.org pages.
  • Repository Filtering: Added client-id parameter support and a corresponding "Repository" facet in the sidebar.
  • Improved Connection Tooltips: Defined and integrated ORGANIZATION_RELATION_TYPE_TOOLTIPS to explain filters like "Affiliated Researcher", "Created By", and "Funded By".
  • Component Extraction: Created a reusable InfoTooltip component to reduce duplication in FacetList.
  • Styling Tweaks: Adjusted MetricsDisplay and WorksDashboard styling for better vertical rhythm and alignment.

Important Technical Details

  • Updated mapSearchParams logic in multiple routes to extract and pass client-id to the data managers.
  • Expanded the Facet type and GraphQL queries to include clients and optional tooltipText.
  • Unified the search path handling to ensure filters persist correctly when using the search box.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Reviewer, please remember our guidelines:

  • Be humble in the language and feedback you give, ask don't tell.
  • Consider using positive language as opposed to neutral when offering feedback. This is to avoid the negative bias that can occur with neutral language appearing negative.
  • Offer suggestions on how to improve code e.g. simplification or expanding clarity.
  • Ensure you give reasons for the changes you are proposing.

Note

Medium Risk
Touches search query parameter mapping, facet data/types, and shared listing UI across several routes, so regressions could affect filtering and navigation; changes are mostly additive UI/data plumbing with limited logic complexity.

Overview
Adds repository-level filtering across Works/Related Works views by introducing a new clients facet and wiring the client-id query param through search/related-content mapSearchParams and the DOI search page variables.

Refactors the sidebar UX: moves/standardizes the SearchBox into the WorksListing facets column (via a new searchBox slot), adjusts related-content headers/layout, and updates the e2e facet expectations (inserting a new “Repository” facet before “Repository Type”).

Improves facet usability by extracting a reusable InfoTooltip, adding optional per-facet tooltipText support (including organization relation type tooltips), and applying minor styling tweaks (metrics spacing, dashboard container classes).

Written by Cursor Bugbot for commit 3f8168b. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features

    • Search box added to Related Works pages and embedded in listings for scoped searches.
    • New client/repository facet to filter works and surface client/repository options.
    • Facet info tooltips provide contextual help for organization-relation facets.
    • Summary metrics now shown inside search/listing results.
  • Improvements

    • Header unified to a static "Related Works" title and synchronized listing/search base paths.
    • Minor styling tweaks to metrics, dashboard spacing, and filter headings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 5, 2026

Walkthrough

Adds propagation of client-id and organization-relation-type into search variables, surfaces clients as a new facet with optional facet tooltips, introduces a reusable InfoTooltip, integrates SearchBox into RelatedContent/WorksListing with derived base URLs, and adjusts layout/styles across several listing and facet components. (50 words)

Changes

Cohort / File(s) Summary
Search param mapping
src/app/(main)/doi.org/.../mapSearchParams.ts, src/app/(main)/orcid.org/[orcid]/mapSearchParams.ts, src/app/(main)/ror.org/[rorid]/mapSearchParams.ts
Added optional "organization-relation-type" and "client-id" to SearchParams; mapSearchparams now sets organizationRelationType (default 'allRelated') and clientId in returned variables.
RelatedContent — SearchBox & URL wiring
src/app/(main)/doi.org/[...doi]/RelatedContent.tsx, src/app/(main)/repositories/[...repoid]/RelatedContent.tsx, src/app/(main)/ror.org/[rorid]/RelatedContent.tsx, src/app/(main)/orcid.org/[orcid]/RelatedContent.tsx
Introduce route-specific derived url used as url + '?', adjust header layout to use a responsive spacer column, and inject SearchBox into WorksListing via new searchBox prop.
Page variables propagation
src/app/(main)/doi.org/page.tsx
Added clientId to the variables object passed into the search/query layer.
WorksListing API & children
src/components/WorksListing/WorksListing.tsx
Added public props searchBox?: React.ReactNode and children?: React.ReactNode; renders searchBox above facets and inserts {children} into right column before loading/content.
SearchBox prop and layout
src/components/SearchBox/SearchBox.tsx, src/components/SearchWork/SearchWork.tsx
Added optional placeholder?: string (default 'Type to search...') to SearchBox; adjusted SearchWork layout to use a responsive spacer column.
WorkFacets & clients facet
src/components/WorkFacets/WorkFacets.tsx, src/data/types.ts, src/data/constants.ts, src/data/queries/searchDoiFacetsQuery.ts
Added clients?: Facet[] to Works and tooltipText?: string to Facet; added client-facets (param client-id), included clients in query conversion, and added clients to FACETS default.
Facet tooltip UI
src/components/InfoTooltip/InfoTooltip.tsx, src/components/FacetList/FacetList.tsx, src/components/FacetList/FacetListItem.tsx
Added reusable InfoTooltip component; FacetList forwards tooltipText and FacetListItem accepts tooltipText? and conditionally renders InfoTooltip.
Organization relation tooltips
src/data/managers/OrganizationRelatedContentManager.ts
Added ORGANIZATION_RELATION_TYPE_TOOLTIPS and extended ORGANIZATION_RELATION_TYPE_FACETS to include optional tooltipText sourced from that mapping.
Styling and dashboard tweaks
src/components/MetricsDisplay/MetricsDisplay.module.scss, src/components/WorksDashboard/WorksDashboard.module.scss, src/components/WorksDashboard/WorksDashboard.tsx
Adjusted MetricsDisplay spacing; removed .graphsContainer margin and replaced dashboard wrapper with utility classes.
Tests
cypress/e2e/searchWork.test.ts
Updated facet header assertion indices due to added facet group (shifts Repository vs Repository Type indices).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as RelatedContent / SearchBox
    participant Listing as WorksListing
    participant Facets as WorkFacets / FacetList
    participant Backend as Query Layer

    User->>UI: open page or type in SearchBox
    UI->>Listing: navigate/update list URL (base url + '?' + params including client-id / organization-relation-type)
    Listing->>Backend: request works with mapped variables
    Backend->>Backend: mapSearchParams -> include clientId, organizationRelationType
    Backend-->>Listing: return QueryData (works, clients, facets with tooltipText)
    Listing->>Facets: render WorkFacets (includes client-facets and searchBox)
    Facets->>User: render facet items with InfoTooltip where present
    User->>Facets: select facet
    Facets->>Listing: trigger filtered fetch
    Listing->>Backend: fetch filtered works
    Backend-->>Listing: return filtered works
    Listing->>User: display filtered results
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • jrhoads
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding repository filtering (client-id parameter, new clients facet) and refactoring the sidebar UI with SearchBox repositioning and layout adjustments across multiple pages.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch funded-ui

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/FacetList/FacetList.tsx (1)

38-48: ⚠️ Potential issue | 🟡 Minor

Minor typo in React key.

Line 40 has an extra space in the key: 'facet-item- ' +id should be 'facet-item-' + id. While this doesn't break functionality, it creates inconsistent key formatting.

Proposed fix
           <FacetListItem
-            key={'facet-item- ' +id + '-' + i}
+            key={'facet-item-' + id + '-' + i}
             facet={facet}
🤖 Fix all issues with AI agents
In `@src/app/`(main)/doi.org/[...doi]/RelatedContent.tsx:
- Line 15: Remove the unused import SummarySearchMetrics from the RelatedContent
component: locate the import statement "import SummarySearchMetrics from
'src/components/SummarySearchMetrics/SummarySearchMetrics'" and delete it (or
remove SummarySearchMetrics from the import list if combined) so the file no
longer imports an identifier that isn't referenced anywhere in
RelatedContent.tsx.

In `@src/app/`(main)/doi.org/page.tsx:
- Around line 24-25: The SearchParams interface is missing hyphenated keys
referenced in page.tsx (you access vars['repository-type'] and vars['client-id']
and earlier vars['resource-type'], vars['field-of-science'],
vars['registration-agency']); add these hyphenated properties to the
SearchParams type (e.g., as optional entries with the same union type used for
other params, such as string | string[] | undefined) so clientType and clientId
assignments are properly typed and consistent with the existing 'resource-type',
'field-of-science', and 'registration-agency' additions.

In `@src/app/`(main)/repositories/[...repoid]/RelatedContent.tsx:
- Around line 56-61: The JSX block in the RelatedContent component has
inconsistent indentation: the opening <Col md={3} className="d-none d-md-block">
line (containing SearchBox) is over-indented compared to surrounding lines; fix
by reducing the leading spaces so the <Col md={3} ...> line and its nested
<SearchBox path={url} /> align with the other sibling <Col md={9}> block and the
file's usual 8-space indenting style (locate this block around the
RelatedContent component and adjust the whitespace only).

In `@src/components/InfoTooltip/InfoTooltip.tsx`:
- Around line 11-27: The InfoTooltip component uses a static Tooltip id
("infoTooltip") and a span with role="button"; replace the static id by calling
React.useId() inside the InfoTooltip component (e.g., const id = React.useId())
and pass that id to the Tooltip (id={id}) and any ARIA attributes as needed to
ensure unique, SSR-safe IDs for each instance (referencing InfoTooltip,
OverlayTrigger, Tooltip). Also remove role="button" from the span since it is
non-actionable (keep onClick stopPropagation), and ensure tabIndex/aria-label
remain appropriate for accessibility.

In `@src/components/WorkFacets/WorkFacets.tsx`:
- Around line 93-95: The current checks using url.startsWith('/repositories')
are brittle for relative or missing-leading-slash inputs; update the logic in
WorkFacets (the component/function where url is inspected) to normalize the URL
before checking the path: create a URL object with a dummy base (e.g. new
URL(url, 'http://example')) and use its pathname.startsWith('/repositories') for
the route check, and apply the same normalization for the other occurrence
mentioned (the check at the second location around line 178) so both branches
reliably detect repository routes regardless of leading slash or relative paths.
🧹 Nitpick comments (1)
src/components/FacetList/FacetListItem.tsx (1)

14-66: Avoid nesting the tooltip’s interactive element inside the Link.

InfoTooltip renders a focusable element (role="button", tabIndex=0), so embedding it inside the anchor can confuse screen readers and keyboard navigation. Consider moving the tooltip outside the <Link> (or making it non-focusable in this context) and verify with an a11y scan.

Comment on lines +24 to +25
clientType: vars['repository-type'],
clientId: vars['client-id']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n src/app/\(main\)/doi.org/page.tsx

Repository: datacite/akita

Length of output: 1351


🏁 Script executed:

find src/data/queries -name "*searchDoiQuery*" -type f

Repository: datacite/akita

Length of output: 92


🏁 Script executed:

cat -n src/data/queries/searchDoiQuery.ts

Repository: datacite/akita

Length of output: 13533


🏁 Script executed:

cat -n tsconfig.json

Repository: datacite/akita

Length of output: 1121


🏁 Script executed:

rg "vars\['" src/app/\(main\)/doi.org/page.tsx

Repository: datacite/akita

Length of output: 272


Add hyphenated params to SearchParams for explicit typing.

vars['repository-type'] and vars['client-id'] are accessed but not declared on SearchParams, leaving these parameters untyped. Note that similar hyphenated keys ('resource-type', 'field-of-science', 'registration-agency') on lines 21-23 have the same issue. Consider adding these to the interface for consistency and type safety.

🔧 Suggested type fix
 interface SearchParams extends Partial<QueryVar> {
   filterQuery?: string
+  "repository-type"?: string
+  "client-id"?: string
+  "resource-type"?: string
+  "field-of-science"?: string
+  "registration-agency"?: string
 }
🤖 Prompt for AI Agents
In `@src/app/`(main)/doi.org/page.tsx around lines 24 - 25, The SearchParams
interface is missing hyphenated keys referenced in page.tsx (you access
vars['repository-type'] and vars['client-id'] and earlier vars['resource-type'],
vars['field-of-science'], vars['registration-agency']); add these hyphenated
properties to the SearchParams type (e.g., as optional entries with the same
union type used for other params, such as string | string[] | undefined) so
clientType and clientId assignments are properly typed and consistent with the
existing 'resource-type', 'field-of-science', and 'registration-agency'
additions.

Comment on lines +93 to 95
"repository-type-facets",
"client-facets"
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat src/components/WorkFacets/WorkFacets.tsx | head -200

Repository: datacite/akita

Length of output: 6190


🏁 Script executed:

rg -n "url\.startsWith\('/repositories" src/components/WorkFacets/WorkFacets.tsx -B3 -A3

Repository: datacite/akita

Length of output: 261


🏁 Script executed:

rg -n "<WorkFacets" --type=tsx -B3 -A3

Repository: datacite/akita

Length of output: 85


🏁 Script executed:

rg -n "SearchOrganization" --type=tsx

Repository: datacite/akita

Length of output: 85


🏁 Script executed:

rg -n "WorkFacets" --type=ts -C3

Repository: datacite/akita

Length of output: 1642


🏁 Script executed:

rg -n "SearchOrganization" --type=ts -C5

Repository: datacite/akita

Length of output: 2771


🏁 Script executed:

fd -e tsx -e ts | xargs rg -l "WorkFacets" | head -20

Repository: datacite/akita

Length of output: 143


🏁 Script executed:

rg -n "url=\|url =" src/components -C2 | head -100

Repository: datacite/akita

Length of output: 40


🏁 Script executed:

cat src/components/WorksListing/WorksListing.tsx

Repository: datacite/akita

Length of output: 3584


🏁 Script executed:

cat src/components/SearchOrganization/SearchOrganization.tsx

Repository: datacite/akita

Length of output: 2891


🏁 Script executed:

rg -n "WorksListing" --type=ts -C5

Repository: datacite/akita

Length of output: 11163


🏁 Script executed:

rg -n "<WorksListing" -C5

Repository: datacite/akita

Length of output: 4888


🏁 Script executed:

grep -n "url=" src/app/\(main\)/repositories/\[\.\.\.\repoid\]/RelatedContent.tsx | head -20

Repository: datacite/akita

Length of output: 84


🏁 Script executed:

cat src/app/\(main\)/repositories/\[\.\.\.\repoid\]/RelatedContent.tsx | sed -n '63,85p'

Repository: datacite/akita

Length of output: 423


🏁 Script executed:

cat src/app/\(main\)/ror.org/\[rorid\]/RelatedContent.tsx | sed -n '72,90p'

Repository: datacite/akita

Length of output: 609


🏁 Script executed:

cat src/components/SearchWork/SearchWork.tsx | sed -n '44,60p'

Repository: datacite/akita

Length of output: 433


🏁 Script executed:

cat src/app/\(main\)/doi.org/\[\.\.\.\doi\]/RelatedContent.tsx | sed -n '69,85p'

Repository: datacite/akita

Length of output: 683


🏁 Script executed:

cat src/app/\(main\)/repositories/\[\.\.\.\repoid\]/RelatedContent.tsx | head -60

Repository: datacite/akita

Length of output: 1963


🏁 Script executed:

cat src/app/\(main\)/ror.org/\[rorid\]/RelatedContent.tsx | head -60

Repository: datacite/akita

Length of output: 2052


🏁 Script executed:

cat src/app/\(main\)/doi.org/\[\.\.\.\doi\]/RelatedContent.tsx | head -60

Repository: datacite/akita

Length of output: 2226


Strengthen URL normalization when checking for repository routes.

The current logic url.startsWith('/repositories') assumes all URLs have a leading slash. While all current callers properly format URLs with leading slashes ('/repositories/...', '/ror.org/...', '/doi.org/...'), the implementation lacks robustness for future cases where relative paths might be passed. The suggested fix using new URL() with a placeholder base normalizes URL parsing and handles edge cases more reliably:

  const defaultActiveKeys = [
    "authors-facets",
    "connection-type-facets",
    "organization-relation-type-facets",
    "published-facets",
    "work-type-facets",
    "license-facets",
    "language-facets",
    "field-of-science-facets",
    "registration-agency-facets",
    "repository-type-facets",
    "client-facets"
  ]
+
+  const isRepositoriesRoute =
+    new URL(url, 'http://placeholder').pathname.startsWith('/repositories')
 
  return (
    <>
@@
-            {!url.startsWith('/repositories') && (
+            {!isRepositoriesRoute && (

Also applies to line 178.

🤖 Prompt for AI Agents
In `@src/components/WorkFacets/WorkFacets.tsx` around lines 93 - 95, The current
checks using url.startsWith('/repositories') are brittle for relative or
missing-leading-slash inputs; update the logic in WorkFacets (the
component/function where url is inspected) to normalize the URL before checking
the path: create a URL object with a dummy base (e.g. new URL(url,
'http://example')) and use its pathname.startsWith('/repositories') for the
route check, and apply the same normalization for the other occurrence mentioned
(the check at the second location around line 178) so both branches reliably
detect repository routes regardless of leading slash or relative paths.

@cypress
Copy link

cypress bot commented Feb 5, 2026

akita    Run #1878

Run Properties:  status check passed Passed #1878  •  git commit cd0d5372fe ℹ️: Merge 6b05f977c9c542c741f4a3ccab69ccdaf519fd5f into 2673848e503dde3603fefabdbbf0...
Project akita
Branch Review funded-ui
Run status status check passed Passed #1878
Run duration 01m 42s
Commit git commit cd0d5372fe ℹ️: Merge 6b05f977c9c542c741f4a3ccab69ccdaf519fd5f into 2673848e503dde3603fefabdbbf0...
Committer Joseph Rhoads
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 2
Tests that did not run due to a developer annotating a test with .skip  Pending 3
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 47
View all changes introduced in this branch ↗︎

fieldOfScience: searchParams['field-of-science'],
registrationAgency: searchParams['registration-agency'],
organizationRelationType: searchParams['organization-relation-type'] || 'allRelated',
clientId: searchParams['client-id'],
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated mapSearchParams logic across four route files

Medium Severity

Four mapSearchParams.ts files (doi.org, orcid.org, ror.org, repositories) contain nearly identical logic for mapping URL search params to query variables. The core mapping of ~10 fields (filterQuery, cursor, contributor, published, resourceTypeId, etc.) is duplicated verbatim. This PR adds organizationRelationType and clientId to three of these files, extending the duplication. Consider extracting a shared utility function that accepts options for route-specific fields like connectionType, clientType, and sort.

Fix in Cursor Fix in Web

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/components/WorkFacets/WorkFacets.tsx (1)

82-93: Consider deriving defaultActiveKeys from rendered facets. This keeps accordion state aligned when repository facets are hidden on repository routes.

Suggested refactor
+  const isRepositoriesRoute = /* your repository route check */
   const defaultActiveKeys = [
     "authors-facets",
     "connection-type-facets",
     "organization-relation-type-facets",
     "published-facets",
     "work-type-facets",
     "license-facets",
     "language-facets",
     "field-of-science-facets",
-    "registration-agency-facets",
-    "repository-type-facets",
-    "client-facets"
+    "registration-agency-facets",
+    ...(isRepositoriesRoute ? [] : ["repository-type-facets", "client-facets"])
   ]

Comment on lines 56 to 62
const url = '/doi.org/' + doi + '/'
return (
<Container fluid>
<Row>
<Col md={{ offset: 3 }}>
<h3 className="member-results" id="title">Related Works - {displayedConnectionTitle}</h3>
<Col md={3} className="d-none d-md-block">
<SearchBox path={url} />
</Col>
Copy link
Contributor

@coderabbitai coderabbitai bot Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, find the files mentioned in the review
find . -name "RelatedContent.tsx" -type f

Repository: datacite/akita

Length of output: 277


🏁 Script executed:

# Also find SearchBox.tsx
find . -name "SearchBox.tsx" -type f

Repository: datacite/akita

Length of output: 98


🏁 Script executed:

# Get the structure to understand the layout
git ls-files | grep -E "(SearchBox|RelatedContent)" | head -20

Repository: datacite/akita

Length of output: 597


🏁 Script executed:

# Examine RelatedContent.tsx around lines 56-62
cat -n ./src/app/\(main\)/doi.org/\[...doi\]/RelatedContent.tsx | sed -n '50,70p'

Repository: datacite/akita

Length of output: 787


🏁 Script executed:

# Get full context of the file to understand searchParams usage
wc -l ./src/app/\(main\)/doi.org/\[...doi\]/RelatedContent.tsx

Repository: datacite/akita

Length of output: 113


🏁 Script executed:

# Read the full RelatedContent.tsx file
cat -n ./src/app/\(main\)/doi.org/\[...doi\]/RelatedContent.tsx

Repository: datacite/akita

Length of output: 3590


🏁 Script executed:

# Now examine SearchBox.tsx to see the onSubmit implementation
cat -n ./src/components/SearchBox/SearchBox.tsx

Repository: datacite/akita

Length of output: 2430


🏁 Script executed:

# Check if the same pattern exists in other RelatedContent files
for file in ./src/app/\(main\)/*/\[*\]/RelatedContent.tsx; do
  echo "=== $file ==="
  grep -n "const url = " "$file" 2>/dev/null || echo "No 'const url' found"
done

Repository: datacite/akita

Length of output: 470


🏁 Script executed:

# Check WorksListing to understand how it handles URL params
grep -n "url" ./src/components/WorksListing/WorksListing.tsx | head -20

Repository: datacite/akita

Length of output: 240


🏁 Script executed:

# Let's look at how WorksListing uses the url prop
cat ./src/components/WorksListing/WorksListing.tsx | head -100

Repository: datacite/akita

Length of output: 3008


🏁 Script executed:

# Check how facets/filters are applied to understand what params should be preserved
grep -n "connectionType\|client-id\|facets" ./src/app/\(main\)/doi.org/\[...doi\]/RelatedContent.tsx

Repository: datacite/akita

Length of output: 439


🏁 Script executed:

# Look at how params are mapped
cat -n ./src/app/\(main\)/doi.org/\[...doi\]/mapSearchParams.ts

Repository: datacite/akita

Length of output: 1560


🏁 Script executed:

# Check what WorkFacets does with the URL
cat -n ./src/components/WorkFacets/WorkFacets.tsx | head -80

Repository: datacite/akita

Length of output: 3644


🏁 Script executed:

# Check if other RelatedContent files also use SearchBox the same way
for file in ./src/app/\(main\)/*/\[*\]/RelatedContent.tsx; do
  echo "=== $(basename $(dirname $file))/RelatedContent.tsx ==="
  grep -A5 "SearchBox" "$file" 2>/dev/null || echo "No SearchBox found"
done

Repository: datacite/akita

Length of output: 1370


🏁 Script executed:

# Check if there's a clear button or param clearing in SearchBox
grep -n "onSearchClear\|replace" ./src/components/SearchBox/SearchBox.tsx

Repository: datacite/akita

Length of output: 158


🏁 Script executed:

# Let's verify the actual behavior by checking if params are preserved anywhere
grep -rn "useSearchParams\|searchParams" ./src/components/SearchBox/ 2>/dev/null

Repository: datacite/akita

Length of output: 240


🏁 Script executed:

# Verify the fixes would work by checking URL construction
node <<'EOF'
// Test the proposed SearchBox fix logic
const testPath = "/doi.org/10.12345/?connection-type=references&client-id=abc";
const searchInput = "water";

const [base, qs] = testPath.split('?');
const params = new URLSearchParams(qs ?? '');
params.set('filterQuery', searchInput);
const result = `${base}?${params.toString()}`;

console.log("Input path:", testPath);
console.log("Search input:", searchInput);
console.log("Result:", result);
console.log("All params preserved:", result.includes('connection-type=references') && result.includes('client-id=abc'));
EOF

Repository: datacite/akita

Length of output: 262


🏁 Script executed:

# Verify the RelatedContent fix logic
node <<'EOF'
// Test the proposed RelatedContent fix logic
const searchParamsObj = new URLSearchParams("connection-type=references&client-id=abc&filterQuery=old");
const url = "/doi.org/10.12345/";

const baseQuery = new URLSearchParams(searchParamsObj.toString());
baseQuery.delete('filterQuery');
const searchPath = baseQuery.toString() ? `${url}?${baseQuery.toString()}` : url;

console.log("Input URL:", url);
console.log("Current params:", searchParamsObj.toString());
console.log("Search path (without filterQuery):", searchPath);
console.log("Filters preserved:", searchPath.includes('connection-type=references') && searchPath.includes('client-id=abc'));
console.log("FilterQuery removed:", !searchPath.includes('filterQuery'));
EOF

Repository: datacite/akita

Length of output: 305


Preserve query parameters when submitting searches in SearchBox.

At lines 56–61, SearchBox receives a bare base URL (/doi.org/{doi}/) and constructs navigation with only ?filterQuery=..., dropping active filter parameters like connection-type, client-id, facet selections, and pagination. This breaks filter persistence when users search after applying filters.

The issue also affects SearchBox.onSearchClear() at line 36, which uses router.replace(path) and loses the current filterQuery parameter.

Apply both fixes below to preserve and merge query parameters correctly:

✅ Fix 1: RelatedContent.tsx (lines 56–61)
-  const url = '/doi.org/' + doi + '/'
+  const url = '/doi.org/' + doi + '/'
+  const baseQuery = new URLSearchParams(searchParams.toString())
+  baseQuery.delete('filterQuery')
+  const searchPath = baseQuery.toString() ? `${url}?${baseQuery.toString()}` : url
   return (
     <Container fluid>
       <Row>
         <Col md={3} className="d-none d-md-block">
-          <SearchBox path={url} />
+          <SearchBox path={searchPath} />
         </Col>
✅ Fix 2: SearchBox.tsx (lines 19–36)
   const onSubmit = () => {
-    if (router)
-      router.push(`${path}?filterQuery=${searchInput}`)
+    if (!router) return
+    const [base, qs] = path.split('?')
+    const params = new URLSearchParams(qs ?? '')
+    params.set('filterQuery', searchInput)
+    router.push(`${base}?${params.toString()}`)
   }

   const onSearchChange = (text: string): void => {
     setSearchInput(text)
   }

   const onSearchClear = () => {
     setSearchInput('')
-    router.replace(path);
+    const [base, qs] = path.split('?')
+    const params = new URLSearchParams(qs ?? '')
+    params.delete('filterQuery')
+    router.replace(params.toString() ? `${base}?${params.toString()}` : base);
   }

Apply the same pattern to src/app/(main)/repositories/[...repoid]/RelatedContent.tsx and src/app/(main)/ror.org/[rorid]/RelatedContent.tsx, which use SearchBox identically.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const url = '/doi.org/' + doi + '/'
return (
<Container fluid>
<Row>
<Col md={{ offset: 3 }}>
<h3 className="member-results" id="title">Related Works - {displayedConnectionTitle}</h3>
<Col md={3} className="d-none d-md-block">
<SearchBox path={url} />
</Col>
const url = '/doi.org/' + doi + '/'
const baseQuery = new URLSearchParams(searchParams.toString())
baseQuery.delete('filterQuery')
const searchPath = baseQuery.toString() ? `${url}?${baseQuery.toString()}` : url
return (
<Container fluid>
<Row>
<Col md={3} className="d-none d-md-block">
<SearchBox path={searchPath} />
</Col>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to address this in a later PR

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jrhoads, I understand—thanks for considering it! Would you like me to create a GitHub issue to track this fix for a later PR? I can capture the details about preserving query parameters in SearchBox and the affected RelatedContent files.

fieldOfScience: searchParams['field-of-science'],
registrationAgency: searchParams['registration-agency'],
organizationRelationType: searchParams['organization-relation-type'] || 'allRelated',
clientId: searchParams['client-id'],
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated mapSearchParams logic across route directories

Medium Severity

The mapSearchparams function and SearchParams interface are duplicated across doi.org, orcid.org, and ror.org route directories with nearly identical implementations. All three map the same core fields (filterQuery, cursor, contributor, published, resourceTypeId, language, license, fieldOfScience, registrationAgency, organizationRelationType, clientId) with only minor variations. This PR had to add client-id to all three files separately.

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to address this in some later work

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/app/`(main)/orcid.org/[orcid]/RelatedContent.tsx:
- Line 54: The base URL variable url currently includes a trailing slash (const
url = '/orcid.org/' + orcid + '/'), which leads to a double slash when later
concatenating '/?' (and similar) — update the definition of url to omit the
trailing slash (e.g., '/orcid.org/' + orcid) or change concatenations to use '?'
instead of '/?' so that constructions like url + '?' produce a single slash;
modify usages around the RelatedContent component where url is joined (lines
referencing url + '/?' near the WorksListing calls) to match the new pattern.
🧹 Nitpick comments (1)
cypress/e2e/searchWork.test.ts (1)

23-34: Consider updating the minimum length assertion for consistency.

The test checks 9 specific facets (indices 0-8), but the minimum length assertion on line 24 only requires .at.least(4). While the individual assertions will catch missing facets, updating this to .at.least(9) would provide a clearer failure message if facets are unexpectedly removed.

💡 Suggested improvement
       .should(($facet) => {
-        expect($facet).to.have.length.at.least(4)
+        expect($facet).to.have.length.at.least(9)
         expect($facet.eq(0)).to.contain('Creators')

</span>
</OverlayTrigger>
)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New InfoTooltip duplicates existing HelpIcon component

Low Severity

The new InfoTooltip component duplicates functionality of the existing HelpIcon component. Both use OverlayTrigger, Tooltip, and faQuestionCircle from the same libraries to render a question mark icon with tooltip text. The stopPropagation and accessibility attributes needed by InfoTooltip could be added as options to HelpIcon instead of creating a separate component.

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will address in later work

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

<span className={styles.facetTitle}>
{facet.title}
{tooltipText && <InfoTooltip text={tooltipText} />}
</span>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tooltip click inside Link causes unintended page navigation

Low Severity

The InfoTooltip is now rendered inside a Next.js Link (<a> tag) in FacetListItem. The tooltip's onClick handler calls e.stopPropagation(), which prevents the Link's click handler from firing. Since the Link's handler is responsible for calling preventDefault() to intercept native navigation, the browser instead follows the <a> href natively, causing a full page reload. Clicking the help icon on organization relation type facets triggers an unintended navigation to the facet URL rather than doing nothing.

Additional Locations (1)

Fix in Cursor Fix in Web

license: searchParams.license,
fieldOfScience: searchParams['field-of-science'],
registrationAgency: searchParams['registration-agency'],
organizationRelationType: searchParams['organization-relation-type'] || 'allRelated',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary organizationRelationType default in DOI and ORCID mapSearchParams

Low Severity

The organizationRelationType variable with a default of 'allRelated' is added to the DOI and ORCID mapSearchParams, but these pages never display an Organization Relation Type facet and have no rorId. The value is consumed by buildOrgQuery, which immediately returns an empty string when rorId is absent, making it a no-op. It only affects the react-query cache key, causing unnecessary cache key variation across these pages. Unlike clientId (which correctly enables the new Repository facet), this variable serves no purpose here and was likely copy-pasted from the ror.org mapSearchParams.

Additional Locations (1)

Fix in Cursor Fix in Web

@jrhoads jrhoads merged commit d8ab8d9 into master Feb 9, 2026
13 checks passed
@jrhoads jrhoads deleted the funded-ui branch February 9, 2026 10:42
@cypress
Copy link

cypress bot commented Feb 9, 2026

akita    Run #1880

Run Properties:  status check passed Passed #1880  •  git commit d8ab8d916b: Merge pull request #564 from datacite/funded-ui
Project akita
Branch Review 1.42.0
Run status status check passed Passed #1880
Run duration 01m 45s
Commit git commit d8ab8d916b: Merge pull request #564 from datacite/funded-ui
Committer Joseph Rhoads
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 1
Tests that did not run due to a developer annotating a test with .skip  Pending 3
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 47
View all changes introduced in this branch ↗︎

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants