Skip to content

[OSDEV-2370] Created reusable data point and drawer components#892

Merged
vlad-shapik merged 30 commits intomainfrom
OSDEV-2370-create-reusable-data-point-and-drawer-components
Mar 6, 2026
Merged

[OSDEV-2370] Created reusable data point and drawer components#892
vlad-shapik merged 30 commits intomainfrom
OSDEV-2370-create-reusable-data-point-and-drawer-components

Conversation

@vlad-shapik
Copy link
Contributor

@vlad-shapik vlad-shapik commented Feb 27, 2026

OSDEV-2370

Created reusable data point and drawer components for the Production Location page redesign:

  • Introduced shared IconComponent (interactive tooltip with icon) and LearnMoreLink; refactored OS ID badge, Data Sources, and Claim status to use them.
  • Added DataPoint component (label, value, status, contributor link, date, and optional "data sources" drawer trigger) and ContributionsDrawer with promoted source and list of contribution cards linking to contributor profiles.
Screenshot 2026-03-05 at 14 36 04 Screenshot 2026-03-05 at 14 36 15 Screenshot 2026-03-05 at 14 36 25
  • Claim form profile step and related tooltips now use IconComponent.

Note

Medium Risk
Medium risk because it introduces new shared UI primitives and refactors multiple Production Location header/claim-flow tooltips, which could change user interactions and rendering across key pages.

Overview
Adds new reusable Production Location UI primitives: DataPoint (label/value with status, contributor link, date, and optional “+N data sources” trigger) and a right-side ContributionsDrawer showing a promoted source plus a list of historical contribution cards.

Introduces shared IconComponent and LearnMoreLink and refactors Production Location header tooltips (OsIdBadge, DataSourcesInfo, ClaimStatusRow) and the claim form ProfileStep help tooltips to use the new pattern; the older interactive DialogTooltip behavior is simplified and InteractiveTrigger is removed. Includes supporting styling/color updates, minor sidebar copy tweaks, and new/updated unit tests for the new components and tooltip test selectors.

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

@vlad-shapik vlad-shapik self-assigned this Feb 27, 2026
@vlad-shapik vlad-shapik marked this pull request as draft February 27, 2026 12:19
@vlad-shapik vlad-shapik force-pushed the OSDEV-2370-create-reusable-data-point-and-drawer-components branch from 8bcdd94 to 599cc04 Compare March 2, 2026 16:35
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:35 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:35 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:35 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:35 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:35 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:35 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:35 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:35 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:35 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:35 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:35 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:35 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:35 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik had a problem deploying to Quality Environment March 2, 2026 16:35 — with GitHub Actions Failure
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:38 — with GitHub Actions Inactive
@barecheck
Copy link

barecheck bot commented Mar 2, 2026

React App | Jest test suite - Code coverage report

Total: 42.37%

Your code coverage diff: 0.44% ▴

✅ All code changes are covered

@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:41 — with GitHub Actions Inactive
@barecheck
Copy link

barecheck bot commented Mar 2, 2026

Dedupe Hub App | Unittest test suite - Code coverage report

Total: 55.73%

Your code coverage diff: 0.00% ▴

✅ All code changes are covered

@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:43 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:43 — with GitHub Actions Inactive
@barecheck
Copy link

barecheck bot commented Mar 2, 2026

Contricleaner App | Unittest test suite - Code coverage report

Total: 98.75%

Your code coverage diff: 0.00% ▴

✅ All code changes are covered

@barecheck
Copy link

barecheck bot commented Mar 2, 2026

Countries App | Unittest test suite - Code coverage report

Total: 100%

Your code coverage diff: 0.00% ▴

✅ All code changes are covered

@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:45 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik had a problem deploying to Quality Environment March 2, 2026 16:45 — with GitHub Actions Failure
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:45 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:45 — with GitHub Actions Inactive
@vlad-shapik vlad-shapik temporarily deployed to Quality Environment March 2, 2026 16:45 — with GitHub Actions Inactive
…k, IconComponent, DataPoint, ContributionsDrawer, ContributionCard, InfoBox)

Made-with: Cursor
- IconComponent: use func instead of elementType for icon prop (prop-types 15.6 compat), fix tooltipVisible className
- LearnMoreLink: use div and linkContainer class (avoid p nesting in tooltips), simplify classes propTypes to object
- DataPoint: export status constants from constants.js only; move wrap/direction/alignItems into styles
- ClaimDataContainer, ProductionLocationDetailsGeneralFields: import STATUS_CLAIMED/STATUS_CROWDSOURCED from DataPoint/constants
- DataSourcesInfo: remove spacing prop from Grid

Made-with: Cursor
…in DataPoint

- ContributionCard, ContributionsDrawer: use userId prop and shape (replace contributorId)
- DataPoint: add userId prop; render contributor name as Link to profile when userId set; use profileRoute from constants; add contributorNameLink styles for link-only styling
- ProductionLocationDetailsGeneralFields: mock data uses userId; pass userId to DataPoint

Made-with: Cursor
…onLocationDetailsGeneralFields

- ClaimDataContainer: remove DataPoint and STATUS_CLAIMED; keep section title only
- ProductionLocationDetailsGeneralFields: remove mock drawer data, ContributionsDrawer, DataPoint usage, data prop; keep Location Identity section title only

Made-with: Cursor
… OsIdBadge; simplify LocationTitle to title only

Made-with: Cursor
…IconComponent

- ContributionsDrawer.test: use shorthand open prop, add aria-label to button
- ContributionCard: add defaultProps for data-testid
- IconComponent: add defaultProps for data-testid

Made-with: Cursor
@coderabbitai
Copy link

coderabbitai bot commented Mar 5, 2026

Caution

Review failed

The head commit changed during the review from 0f3a467 to b53a51a.

📝 Walkthrough

Walkthrough

Introduces reusable IconComponent and LearnMoreLink components, creates new DataPoint and ContributionsDrawer components with supporting subcomponents for production location details, simplifies DialogTooltip by removing interactive behavior, and replaces existing tooltip implementations across multiple components with the new IconComponent.

Changes

Cohort / File(s) Summary
Reusable Icon & Link Components
src/react/src/components/Shared/IconComponent/IconComponent.jsx, src/react/src/components/Shared/IconComponent/hooks.js, src/react/src/components/Shared/IconComponent/styles.js, src/react/src/components/Shared/IconComponent/constants.js, src/react/src/components/ProductionLocation/Shared/LearnMoreLink/LearnMoreLink.jsx, src/react/src/components/ProductionLocation/Shared/LearnMoreLink/styles.js, src/react/src/components/ProductionLocation/Shared/LearnMoreLink/constants.js
New IconComponent with tooltip and custom hook for state management; new LearnMoreLink component for styled links with arrow text.
DataPoint Component & Utilities
src/react/src/components/ProductionLocation/DataPoint/DataPoint.jsx, src/react/src/components/ProductionLocation/DataPoint/styles.js, src/react/src/components/ProductionLocation/DataPoint/constants.js, src/react/src/components/ProductionLocation/DataPoint/utils.js
New DataPoint component displaying labeled values with optional status chip, contributor link, date, and drawer trigger; includes styling and utility functions for source count retrieval.
ContributionsDrawer & Subcomponents
src/react/src/components/ProductionLocation/ContributionsDrawer/ContributionsDrawer.jsx, src/react/src/components/ProductionLocation/ContributionsDrawer/styles.js, src/react/src/components/ProductionLocation/ContributionsDrawer/constants.js, src/react/src/components/ProductionLocation/ContributionsDrawer/utils.js, src/react/src/components/ProductionLocation/ContributionsDrawer/ContributionCard/*, src/react/src/components/ProductionLocation/ContributionsDrawer/InfoBox/*, src/react/src/components/ProductionLocation/ContributionsDrawer/DrawerSubtitle/*, src/react/src/components/ProductionLocation/ContributionsDrawer/InfoPromotedText/*
New drawer component for displaying contributions list with promoted section; includes subcomponents for contribution cards, info boxes, subtitle with contributor count, and promoted text; comprehensive styling and utility functions.
DialogTooltip Simplification & InteractiveTrigger Removal
src/react/src/components/Contribute/DialogTooltip.jsx, src/react/src/components/Contribute/InteractiveTrigger.jsx
Removed interactive tooltip functionality, timers, and state management from DialogTooltip; completely removed InteractiveTrigger component and its event handling logic.
Tooltip Replacements in Existing Components
src/react/src/components/ProductionLocation/Heading/ClaimFlag/ClaimStatusRow.jsx, src/react/src/components/ProductionLocation/Heading/DataSourcesInfo/DataSourcesInfo.jsx, src/react/src/components/ProductionLocation/Heading/osIdBadge/OsIdBadge.jsx
Replaced DialogTooltip usage with new IconComponent; updated imports and consolidated tooltip with LearnMoreLink content.
ProfileStep & Related Styles
src/react/src/components/InitialClaimFlow/ClaimForm/Steps/ProfileStep/ProfileStep.jsx, src/react/src/components/InitialClaimFlow/ClaimForm/Steps/ProfileStep/styles.js
Replaced Tooltip/HelpOutline/IconButton with IconComponent for help hints; removed tooltip-related styling entries; added helpTooltip margin styling.
Test Updates
src/react/src/__tests__/components/ContributionsDrawer.test.jsx, src/react/src/__tests__/components/DataPoint.test.jsx, src/react/src/__tests__/components/DataSourcesInfo.test.jsx, src/react/src/__tests__/components/OsIdBadge.test.jsx
New test suites for ContributionsDrawer and DataPoint; updated existing tests to query by data-testid instead of accessible names.
UI Copy & Typography Updates
src/react/src/components/ProductionLocation/Sidebar/ContributeFields/ContributeFields.jsx, src/react/src/components/ProductionLocation/Sidebar/ContributeFields/styles.js, src/react/src/components/ProductionLocation/Sidebar/NavBar/styles.js, src/react/src/components/ProductionLocation/Heading/LocationTitle/styles.js
Updated subtitle copy and button labels; increased font sizes for title and label typography across multiple components.
Minor Updates
src/react/src/components/ProductionLocation/ProductionLocationDetailsContent/ProductionLocationDetailsContent.jsx, doc/release/RELEASE-NOTES.md
Import path correction for OsIdBadge; added data prop to GeneralFields; release notes documentation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PR #778 — Modifies ProfileStep implementation, overlapping with the ProfileStep tooltip refactoring changes in this PR.
  • PR #540 — Simplifies DialogTooltip-based tooltip behavior across claim components, directly related to the DialogTooltip API changes.
  • PR #901 — Updates ProductionLocation heading and OsIdBadge UI components that are refactored in this PR.

Suggested reviewers

  • protsack-stephan
  • VadimKovalenkoSNF
  • roman-stolar
  • mazursasha1990
🚥 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
Title check ✅ Passed The title accurately summarizes the main change: creation of reusable data point and drawer components, which is the primary focus across most files in the changeset.
Description check ✅ Passed The description is directly related to the changeset, detailing the introduction of IconComponent, LearnMoreLink, DataPoint, ContributionsDrawer, and refactoring of existing components to use them.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch OSDEV-2370-create-reusable-data-point-and-drawer-components

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

@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

🧹 Nitpick comments (9)
src/react/src/components/ProductionLocation/Sidebar/ContributeFields/styles.js (1)

12-12: Use px units for these typography sizes to stay consistent with project style conventions.

On Line 12, Line 16, and Line 53, the updated values are in rem; please convert these to px to align with the repository’s typography unit pattern.

Proposed diff
-            fontSize: '1.25rem',
+            fontSize: '20px',
...
-            fontSize: '1rem',
+            fontSize: '16px',
...
-            fontSize: '1.15rem',
+            fontSize: '18.4px',

Based on learnings: In the Open Supply Hub project, font sizes are expected to use direct px units consistently.

Also applies to: 16-16, 53-53

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/react/src/components/ProductionLocation/Sidebar/ContributeFields/styles.js`
at line 12, The style definitions in
src/react/src/components/ProductionLocation/Sidebar/ContributeFields/styles.js
use rem units for typography (e.g., fontSize: '1.25rem' and the other two
fontSize entries) but the project requires px units; update each fontSize
property in the ContributeFields styles to use equivalent pixel values (e.g.,
convert '1.25rem' to '20px' or the project-standard px equivalents) so all
fontSize declarations in that file use px instead of rem while keeping the same
visual size.
src/react/src/components/Shared/IconComponent/hooks.js (1)

34-35: Clear any pending close timer on popper leave for safer state handling.

Line 34 currently closes immediately but does not cancel a pending timer first; clearing it keeps behavior robust as interactions evolve.

🛠️ Optional hardening
-    const handlePopperLeave = useCallback(() => setOpen(false), []);
+    const handlePopperLeave = useCallback(() => {
+        clearCloseTimer();
+        setOpen(false);
+    }, [clearCloseTimer]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/react/src/components/Shared/IconComponent/hooks.js` around lines 34 - 35,
handlePopperLeave currently just calls setOpen(false) without cancelling any
pending close timer; update it to first clear the pending timeout (e.g.
clearTimeout on the ref/variable used to store the close timer such as
closeTimerRef or pendingCloseTimer) and then call setOpen(false) so any
outstanding timers are cancelled before changing state — locate
handlePopperLeave in hooks.js and ensure it references and clears the existing
timer holder (clearTimeout(closeTimerRef.current) or equivalent) before
setOpen(false).
src/react/src/components/ProductionLocation/ProductionLocationDetailsContent/ProductionLocationDetailsContent.jsx (1)

56-56: Remove the unused data prop passed to GeneralFields.

Line 56 passes data, but ProductionLocationDetailsGeneralFields currently does not consume it, so this is a silent no-op.

♻️ Proposed cleanup
-                    <GeneralFields data={data} />
+                    <GeneralFields />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/react/src/components/ProductionLocation/ProductionLocationDetailsContent/ProductionLocationDetailsContent.jsx`
at line 56, Remove the unused data prop being passed to the GeneralFields
component: update the JSX in ProductionLocationDetailsContent to stop passing
data (change the usage of GeneralFields in this file to just <GeneralFields />)
and verify that the GeneralFields component (a.k.a.
ProductionLocationDetailsGeneralFields) does not expect or use a data prop—if it
does not, remove any unused prop from its props signature; if it does need data,
instead wire the correct prop name/source. Ensure there are no other references
to the now-removed prop in this component.
src/react/src/components/ProductionLocation/DataPoint/styles.js (1)

9-37: Show tooltip icon on keyboard focus, not only hover.

Line 9 reveals the icon on :hover while Line 35 keeps it hidden by default. Add a focus-based rule so keyboard navigation has equivalent discoverability.

♿ Suggested accessibility tweak
         root: Object.freeze({
             paddingTop: '12px',
             paddingBottom: '12px',
             flexWrap: 'nowrap',
             '&:hover $tooltipIcon': Object.freeze({
                 opacity: 1,
                 '& > svg': Object.freeze({
                     '&:hover': Object.freeze({
                         color: COLOURS.PURPLE,
                     }),
                 }),
             }),
+            '&:focus-within $tooltipIcon': Object.freeze({
+                opacity: 1,
+            }),
         }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/react/src/components/ProductionLocation/DataPoint/styles.js` around lines
9 - 37, The tooltip icon is only revealed on hover via the selector '&:hover
$tooltipIcon' while 'tooltipIcon' defaults to opacity: 0, which hides it from
keyboard users; update the parent hover rule(s) in styles.js (the block
containing '&:hover $tooltipIcon') to also target keyboard focus by adding
equivalent selectors such as '&:focus-within $tooltipIcon' and/or '&:focus
$tooltipIcon' so that the tooltipIcon becomes visible when a child receives
focus, ensuring keyboard discoverability for the elements using labelColumn,
labelItem, label, tooltipIconItem and tooltipIcon.
src/react/src/components/ProductionLocation/DataPoint/DataPoint.jsx (1)

144-163: Remove redundant fragment in the date block.

The fragment wraps a single <Grid> child and can be dropped for cleaner JSX.

♻️ Proposed cleanup
-                            {date ? (
-                                <>
-                                    <Grid item className={classes.dateItem}>
-                                        <span
-                                            className={classes.dateBlock}
-                                            data-testid="data-point-date"
-                                        >
-                                            <ScheduleIcon
-                                                fontSize="small"
-                                                className={classes.dateIcon}
-                                            />
-                                            <Typography
-                                                variant="body2"
-                                                component="span"
-                                                className={classes.dateText}
-                                            >
-                                                {formatDisplayDate(date)}
-                                            </Typography>
-                                        </span>
-                                    </Grid>
-                                </>
-                            ) : null}
+                            {date ? (
+                                <Grid item className={classes.dateItem}>
+                                    <span
+                                        className={classes.dateBlock}
+                                        data-testid="data-point-date"
+                                    >
+                                        <ScheduleIcon
+                                            fontSize="small"
+                                            className={classes.dateIcon}
+                                        />
+                                        <Typography
+                                            variant="body2"
+                                            component="span"
+                                            className={classes.dateText}
+                                        >
+                                            {formatDisplayDate(date)}
+                                        </Typography>
+                                    </span>
+                                </Grid>
+                            ) : null}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/react/src/components/ProductionLocation/DataPoint/DataPoint.jsx` around
lines 144 - 163, Remove the redundant React fragment wrapping the single Grid
node in the DataPoint component: locate the JSX in DataPoint.jsx where a
fragment encloses <Grid item className={classes.dateItem}> (the block that
renders ScheduleIcon, Typography and {formatDisplayDate(date)}) and delete the
surrounding <>...</> so the Grid is returned directly; ensure indentation
remains correct and tests using data-testid="data-point-date" still target the
same element.
src/react/src/__tests__/components/DataPoint.test.jsx (1)

83-93: Add a positive-path test for sources button interaction.

This block only asserts the hidden state. Please also cover the branch where contributions exist and verify onOpenDrawer is called on click.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/react/src/__tests__/components/DataPoint.test.jsx` around lines 83 - 93,
Add a positive-path test next to the current one that renders the component via
renderDataPoint with drawerData.contributions set to a non-empty array and a
jest.fn() for onOpenDrawer, assert the sources button
(data-point-sources-button) is present, simulate a click (using userEvent.click
or fireEvent.click) on that button, and assert onOpenDrawer was called;
reference the existing renderDataPoint helper, the data-point-sources-button
test id, and the onOpenDrawer mock to implement the test.
src/react/src/components/ProductionLocation/ContributionsDrawer/styles.js (1)

3-4: Consider naming the exported function (static analysis hint).

SonarCloud flags the anonymous arrow function. While this pattern is consistent with other style files in the codebase (e.g., profileStepStyles), naming the function improves stack traces and debugging.

♻️ Optional: Name the function
-export default () =>
+export default function contributionsDrawerStyles() {
+    return Object.freeze({
-    Object.freeze({
         drawerPaper: Object.freeze({

Or keep the arrow function but assign it:

-export default () =>
+const contributionsDrawerStyles = () =>
     Object.freeze({
         // ...styles
     });
+
+export default contributionsDrawerStyles;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/react/src/components/ProductionLocation/ContributionsDrawer/styles.js`
around lines 3 - 4, The exported anonymous arrow function should be given a name
to improve stack traces and satisfy static analysis: replace the default
anonymous export used in this module (export default () => Object.freeze({...}))
with a named function or named constant (e.g., contributionsDrawerStyles or
getContributionsDrawerStyles) and export that name as the default; update the
function declaration that returns Object.freeze(...) so the symbol is
identifiable in stack traces and tooling.
src/react/src/__tests__/components/ContributionsDrawer.test.jsx (1)

44-49: Minor redundancy in test props.

The renderContributionsDrawer helper already sets open to true by default (line 15), so passing open: true again in the test is redundant. This is a very minor observation and doesn't affect test correctness.

♻️ Optional cleanup
     test('renders without crashing when open with required props', () => {
-        renderContributionsDrawer({ open: true, onClose: () => {} });
+        renderContributionsDrawer({ onClose: () => {} });

         expect(screen.getByTestId('contributions-drawer')).toBeInTheDocument();
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/react/src/__tests__/components/ContributionsDrawer.test.jsx` around lines
44 - 49, The test for ContributionsDrawer redundantly passes open: true even
though the renderContributionsDrawer helper already defaults open to true;
update the test that calls renderContributionsDrawer({ open: true, onClose: ()
=> {} }) to simply call renderContributionsDrawer({ onClose: () => {} }) (leave
the onClose stub) so the test remains the same but without the duplicate open
prop referring to the renderContributionsDrawer helper and ContributionsDrawer
rendering.
src/react/src/components/ProductionLocation/ContributionsDrawer/InfoBox/InfoBox.jsx (1)

1-8: Prefer the shared LearnMoreLink here to avoid duplicated link behavior.

This file re-implements external-link markup that the new shared LearnMoreLink already standardizes. Reusing it will keep behavior and styling consistent across the redesign.

♻️ Suggested refactor
 import React from 'react';
 import { object, string, node, oneOf } from 'prop-types';
 import Typography from '@material-ui/core/Typography';
 import InfoIcon from '@material-ui/icons/InfoOutlined';
 import { withStyles } from '@material-ui/core/styles';
+import LearnMoreLink from '../../Shared/LearnMoreLink/LearnMoreLink';
@@
-            {learnMoreUrl && learnMoreLabel ? (
-                <a
-                    href={learnMoreUrl}
-                    target="_blank"
-                    rel="noopener noreferrer"
-                    className={learnMoreLinkClass}
-                >
-                    {learnMoreLabel}
-                    <span className={classes.learnMoreArrow}>→</span>
-                </a>
-            ) : null}
+            {learnMoreUrl && learnMoreLabel ? (
+                <LearnMoreLink href={learnMoreUrl}>
+                    <span className={learnMoreLinkClass}>
+                        {learnMoreLabel}
+                        <span className={classes.learnMoreArrow}>→</span>
+                    </span>
+                </LearnMoreLink>
+            ) : null}

Also applies to: 42-52

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/react/src/components/ProductionLocation/ContributionsDrawer/InfoBox/InfoBox.jsx`
around lines 1 - 8, The InfoBox component currently re-implements external-link
markup; replace that duplicated markup with the shared LearnMoreLink component
by importing LearnMoreLink and using it where the external anchor/link is
rendered in InfoBox (replace the current anchor/markup in the render of the
InfoBox component). Remove any local external-link class/markup and pass the
same href, children/text, and styling/className to LearnMoreLink so behavior and
styling match the shared implementation; update propTypes if needed to accept
props forwarded to LearnMoreLink and remove any now-unused local link-specific
code (keep infoBoxStyles and Icon usage intact).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/react/src/components/InitialClaimFlow/ClaimForm/Steps/ProfileStep/ProfileStep.jsx`:
- Around line 137-140: The IconComponent currently renders a non-focusable span
(used with classes.helpTooltip) and only handles mouse events; update
IconComponent so the trigger is keyboard-accessible by adding tabIndex={0}, a
semantic role (e.g., role="button" or role="img" as appropriate), and onKeyDown
handler that mirrors the existing onMouseEnter/onMouseLeave behavior (e.g.,
open/close tooltip on Enter/Space and Escape) so Material-UI Tooltip receives
focus events; ensure these handlers delegate to the same internal show/hide
logic the mouse events use and preserve existing props passed where
IconComponent is used.

In
`@src/react/src/components/ProductionLocation/ContributionsDrawer/ContributionsDrawer.jsx`:
- Line 92: The Divider in ContributionsDrawer.jsx is using an unsupported
height={1} prop; remove the height prop from the Divider component and replace
it with a CSS class (e.g., className="thinDivider") that sets the desired
thickness via CSS (height or border-top/border-bottom) and margin as needed. Add
the CSS rule in the component's styling mechanism (makeStyles, withStyles, or a
module stylesheet used by ContributionsDrawer) and apply the class to the
Divider instance so the visual thickness is controlled by CSS rather than a DOM
prop.

In `@src/react/src/components/ProductionLocation/ContributionsDrawer/utils.jsx`:
- Around line 6-19: The promotional paragraph in ContributionsDrawer utils.jsx
contains a duplicated clause ("with the OS ID, preferred data entry, and
justification")—remove the redundant copy that appears after the Support anchor
link and keep the initial instance earlier in the sentence; ensure spacing and
punctuation around the <a className={classes.supportLink}>Support</a> anchor
remain correct so the sentence reads once and flows naturally.

In `@src/react/src/components/ProductionLocation/DataPoint/DataPoint.jsx`:
- Around line 109-114: The conditional currently treats an empty string as valid
(userId != null) and renders a broken Link; update the check used around the
Link rendering in the DataPoint.jsx component to ensure userId is non-empty
(e.g., require a truthy, non-empty string) before calling
profileRoute.replace(':id', String(userId)); specifically, change the condition
guarding the Link from userId != null to a check that excludes empty strings
(for example userId && String(userId).trim() !== '') so the Link is only
rendered when a real userId exists.

In `@src/react/src/components/Shared/IconComponent/IconComponent.jsx`:
- Around line 42-49: The span used as the tooltip trigger is not
keyboard-accessible; update the element (the JSX using className,
classes.defaultTooltipIcon, open, dataTestId) to behave like a focusable control
by adding tabIndex={0}, a suitable ARIA role (e.g., role="button" or
aria-haspopup="true"), and keyboard event handlers that mirror
handleTriggerEnter/handleTriggerLeave (e.g., onFocus -> handleTriggerEnter,
onBlur -> handleTriggerLeave, and onKeyDown to open/close on
Enter/Escape/Space); ensure these handlers call the existing handleTriggerEnter
and handleTriggerLeave functions so the tooltip works for keyboard users as well
as mouse users.

---

Nitpick comments:
In `@src/react/src/__tests__/components/ContributionsDrawer.test.jsx`:
- Around line 44-49: The test for ContributionsDrawer redundantly passes open:
true even though the renderContributionsDrawer helper already defaults open to
true; update the test that calls renderContributionsDrawer({ open: true,
onClose: () => {} }) to simply call renderContributionsDrawer({ onClose: () =>
{} }) (leave the onClose stub) so the test remains the same but without the
duplicate open prop referring to the renderContributionsDrawer helper and
ContributionsDrawer rendering.

In `@src/react/src/__tests__/components/DataPoint.test.jsx`:
- Around line 83-93: Add a positive-path test next to the current one that
renders the component via renderDataPoint with drawerData.contributions set to a
non-empty array and a jest.fn() for onOpenDrawer, assert the sources button
(data-point-sources-button) is present, simulate a click (using userEvent.click
or fireEvent.click) on that button, and assert onOpenDrawer was called;
reference the existing renderDataPoint helper, the data-point-sources-button
test id, and the onOpenDrawer mock to implement the test.

In
`@src/react/src/components/ProductionLocation/ContributionsDrawer/InfoBox/InfoBox.jsx`:
- Around line 1-8: The InfoBox component currently re-implements external-link
markup; replace that duplicated markup with the shared LearnMoreLink component
by importing LearnMoreLink and using it where the external anchor/link is
rendered in InfoBox (replace the current anchor/markup in the render of the
InfoBox component). Remove any local external-link class/markup and pass the
same href, children/text, and styling/className to LearnMoreLink so behavior and
styling match the shared implementation; update propTypes if needed to accept
props forwarded to LearnMoreLink and remove any now-unused local link-specific
code (keep infoBoxStyles and Icon usage intact).

In `@src/react/src/components/ProductionLocation/ContributionsDrawer/styles.js`:
- Around line 3-4: The exported anonymous arrow function should be given a name
to improve stack traces and satisfy static analysis: replace the default
anonymous export used in this module (export default () => Object.freeze({...}))
with a named function or named constant (e.g., contributionsDrawerStyles or
getContributionsDrawerStyles) and export that name as the default; update the
function declaration that returns Object.freeze(...) so the symbol is
identifiable in stack traces and tooling.

In `@src/react/src/components/ProductionLocation/DataPoint/DataPoint.jsx`:
- Around line 144-163: Remove the redundant React fragment wrapping the single
Grid node in the DataPoint component: locate the JSX in DataPoint.jsx where a
fragment encloses <Grid item className={classes.dateItem}> (the block that
renders ScheduleIcon, Typography and {formatDisplayDate(date)}) and delete the
surrounding <>...</> so the Grid is returned directly; ensure indentation
remains correct and tests using data-testid="data-point-date" still target the
same element.

In `@src/react/src/components/ProductionLocation/DataPoint/styles.js`:
- Around line 9-37: The tooltip icon is only revealed on hover via the selector
'&:hover $tooltipIcon' while 'tooltipIcon' defaults to opacity: 0, which hides
it from keyboard users; update the parent hover rule(s) in styles.js (the block
containing '&:hover $tooltipIcon') to also target keyboard focus by adding
equivalent selectors such as '&:focus-within $tooltipIcon' and/or '&:focus
$tooltipIcon' so that the tooltipIcon becomes visible when a child receives
focus, ensuring keyboard discoverability for the elements using labelColumn,
labelItem, label, tooltipIconItem and tooltipIcon.

In
`@src/react/src/components/ProductionLocation/ProductionLocationDetailsContent/ProductionLocationDetailsContent.jsx`:
- Line 56: Remove the unused data prop being passed to the GeneralFields
component: update the JSX in ProductionLocationDetailsContent to stop passing
data (change the usage of GeneralFields in this file to just <GeneralFields />)
and verify that the GeneralFields component (a.k.a.
ProductionLocationDetailsGeneralFields) does not expect or use a data prop—if it
does not, remove any unused prop from its props signature; if it does need data,
instead wire the correct prop name/source. Ensure there are no other references
to the now-removed prop in this component.

In
`@src/react/src/components/ProductionLocation/Sidebar/ContributeFields/styles.js`:
- Line 12: The style definitions in
src/react/src/components/ProductionLocation/Sidebar/ContributeFields/styles.js
use rem units for typography (e.g., fontSize: '1.25rem' and the other two
fontSize entries) but the project requires px units; update each fontSize
property in the ContributeFields styles to use equivalent pixel values (e.g.,
convert '1.25rem' to '20px' or the project-standard px equivalents) so all
fontSize declarations in that file use px instead of rem while keeping the same
visual size.

In `@src/react/src/components/Shared/IconComponent/hooks.js`:
- Around line 34-35: handlePopperLeave currently just calls setOpen(false)
without cancelling any pending close timer; update it to first clear the pending
timeout (e.g. clearTimeout on the ref/variable used to store the close timer
such as closeTimerRef or pendingCloseTimer) and then call setOpen(false) so any
outstanding timers are cancelled before changing state — locate
handlePopperLeave in hooks.js and ensure it references and clears the existing
timer holder (clearTimeout(closeTimerRef.current) or equivalent) before
setOpen(false).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0a0a3082-c5fb-464f-90ca-ad612cb1be68

📥 Commits

Reviewing files that changed from the base of the PR and between a8eb969 and bf20cb1.

📒 Files selected for processing (35)
  • doc/release/RELEASE-NOTES.md
  • src/react/src/__tests__/components/ContributionsDrawer.test.jsx
  • src/react/src/__tests__/components/DataPoint.test.jsx
  • src/react/src/__tests__/components/DataSourcesInfo.test.jsx
  • src/react/src/__tests__/components/OsIdBadge.test.jsx
  • src/react/src/components/Contribute/DialogTooltip.jsx
  • src/react/src/components/Contribute/InteractiveTrigger.jsx
  • src/react/src/components/InitialClaimFlow/ClaimForm/Steps/ProfileStep/ProfileStep.jsx
  • src/react/src/components/InitialClaimFlow/ClaimForm/Steps/ProfileStep/styles.js
  • src/react/src/components/ProductionLocation/ContributionsDrawer/ContributionCard/ContributionCard.jsx
  • src/react/src/components/ProductionLocation/ContributionsDrawer/ContributionCard/styles.js
  • src/react/src/components/ProductionLocation/ContributionsDrawer/ContributionsDrawer.jsx
  • src/react/src/components/ProductionLocation/ContributionsDrawer/InfoBox/InfoBox.jsx
  • src/react/src/components/ProductionLocation/ContributionsDrawer/InfoBox/styles.js
  • src/react/src/components/ProductionLocation/ContributionsDrawer/constants.js
  • src/react/src/components/ProductionLocation/ContributionsDrawer/styles.js
  • src/react/src/components/ProductionLocation/ContributionsDrawer/utils.jsx
  • src/react/src/components/ProductionLocation/DataPoint/DataPoint.jsx
  • src/react/src/components/ProductionLocation/DataPoint/constants.js
  • src/react/src/components/ProductionLocation/DataPoint/styles.js
  • src/react/src/components/ProductionLocation/DataPoint/utils.js
  • src/react/src/components/ProductionLocation/Heading/ClaimFlag/ClaimStatusRow.jsx
  • src/react/src/components/ProductionLocation/Heading/DataSourcesInfo/DataSourcesInfo.jsx
  • src/react/src/components/ProductionLocation/Heading/osIdBadge/OsIdBadge.jsx
  • src/react/src/components/ProductionLocation/ProductionLocationDetailsContent/ProductionLocationDetailsContent.jsx
  • src/react/src/components/ProductionLocation/Shared/LearnMoreLink/LearnMoreLink.jsx
  • src/react/src/components/ProductionLocation/Shared/LearnMoreLink/constants.js
  • src/react/src/components/ProductionLocation/Shared/LearnMoreLink/styles.js
  • src/react/src/components/ProductionLocation/Sidebar/ContributeFields/ContributeFields.jsx
  • src/react/src/components/ProductionLocation/Sidebar/ContributeFields/styles.js
  • src/react/src/components/ProductionLocation/utils.js
  • src/react/src/components/Shared/IconComponent/IconComponent.jsx
  • src/react/src/components/Shared/IconComponent/constants.js
  • src/react/src/components/Shared/IconComponent/hooks.js
  • src/react/src/components/Shared/IconComponent/styles.js
💤 Files with no reviewable changes (1)
  • src/react/src/components/Contribute/InteractiveTrigger.jsx

Copy link
Collaborator

@protsack-stephan protsack-stephan left a comment

Choose a reason for hiding this comment

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

Great work! Couple small comments from me.

Copy link
Contributor

@VadimKovalenkoSNF VadimKovalenkoSNF left a comment

Choose a reason for hiding this comment

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

Looks good, but request few changes.

- LocationTitle: set titleAccent fontSize to 1.15rem
- NavBar: title 1.25rem, menuLabel 1.15rem

Made-with: Cursor
…xt, utils

- Add DrawerSubtitle component with dynamic field subtitle
- Add InfoPromotedText component (replace getInfoPromotedText)
- Add utils.js: getContributionsCount, getContributionsSectionLabel, getUniqueContributorCount
- Remove utils.jsx; move subtitle/fieldName styles to DrawerSubtitle
- Simplify ContributionsDrawer and InfoBox

Made-with: Cursor
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 Free Tier Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Case-sensitive import path breaks on Linux
    • Updated the OsIdBadge import to use the correct lowercase osIdBadge directory so module resolution works on case-sensitive filesystems.
  • ✅ Fixed: IconComponent tooltip inaccessible to keyboard users
    • Made the tooltip trigger keyboard-focusable and added focus/blur and keydown handling (plus popper focus handling) so keyboard users can open and interact with tooltip content.

Create PR

Or push these changes by commenting:

@cursor push 44cbe8d5d1
Preview (44cbe8d5d1)
diff --git a/src/react/src/components/ProductionLocation/ProductionLocationDetailsContent/ProductionLocationDetailsContent.jsx b/src/react/src/components/ProductionLocation/ProductionLocationDetailsContent/ProductionLocationDetailsContent.jsx
--- a/src/react/src/components/ProductionLocation/ProductionLocationDetailsContent/ProductionLocationDetailsContent.jsx
+++ b/src/react/src/components/ProductionLocation/ProductionLocationDetailsContent/ProductionLocationDetailsContent.jsx
@@ -17,7 +17,7 @@
 import { facilityClaimStatusChoicesEnum } from '../../../util/constants';
 
 import productionLocationDetailsContentStyles from './styles';
-import OsIdBadge from '../Heading/OsIdBadge/OsIdBadge';
+import OsIdBadge from '../Heading/osIdBadge/OsIdBadge';
 
 const ProductionLocationDetailsContent = ({
     classes,

diff --git a/src/react/src/components/Shared/IconComponent/IconComponent.jsx b/src/react/src/components/Shared/IconComponent/IconComponent.jsx
--- a/src/react/src/components/Shared/IconComponent/IconComponent.jsx
+++ b/src/react/src/components/Shared/IconComponent/IconComponent.jsx
@@ -24,7 +24,17 @@
         handlePopperEnter,
         handlePopperLeave,
     } = useInteractiveTooltip();
+    const handleTriggerKeyDown = event => {
+        if (event.key === 'Enter' || event.key === ' ') {
+            event.preventDefault();
+            handleTriggerEnter();
+        }
 
+        if (event.key === 'Escape') {
+            setOpen(false);
+        }
+    };
+
     return (
         <Tooltip
             title={title}
@@ -37,14 +47,21 @@
             PopperProps={{
                 onMouseEnter: handlePopperEnter,
                 onMouseLeave: handlePopperLeave,
+                onFocus: handlePopperEnter,
+                onBlur: handlePopperLeave,
             }}
         >
             <span
                 className={`${className || ''} ${classes.defaultTooltipIcon} ${
                     open ? classes.tooltipVisible : ''
                 }`}
+                role="button"
+                tabIndex={0}
                 onMouseEnter={handleTriggerEnter}
                 onMouseLeave={handleTriggerLeave}
+                onFocus={handleTriggerEnter}
+                onBlur={handleTriggerLeave}
+                onKeyDown={handleTriggerKeyDown}
                 data-testid={dataTestId}
             >
                 <Icon className={classes.icon} fontSize="small" />
This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

…esystems

- Rename Heading/osIdBadge to Heading/OsIdBadge so imports resolve on
  Linux/CI (case-sensitive FS); update OsIdBadge.test.jsx import path
- Add DataPoint SourcesButton component (styles, utils) and adjust
  DataPoint layout/styles
- Tweak ContributionsDrawer, ContributionCard, DrawerSubtitle styles
  and utils; remove unused drawer style
- Update ProductionLocationDetails and Sidebar NavBar styles
- Add COLOURS entries; remove unused ProductionLocation/utils.js

Made-with: Cursor
Use uppercase hex for CLAIMED_CHIP_BG and CROWDSOURCED_CHIP_BG for
consistency with other colour constants.

Made-with: Cursor
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 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 6, 2026

Copy link
Contributor

@VadimKovalenkoSNF VadimKovalenkoSNF left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Collaborator

@protsack-stephan protsack-stephan left a comment

Choose a reason for hiding this comment

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

Good work!

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