Skip to content

Feature/add order details components#229

Merged
smarcet merged 8 commits intomainfrom
feature/add-order-details-components
May 4, 2026
Merged

Feature/add order details components#229
smarcet merged 8 commits intomainfrom
feature/add-order-details-components

Conversation

@santipalenque
Copy link
Copy Markdown
Contributor

@santipalenque santipalenque commented Apr 28, 2026

https://app.clickup.com/t/86b66n5k4

Summary by CodeRabbit

  • New Features

    • Added three new card layout options (Inline, List, Table) for flexible content presentation.
    • Introduced specialized table row components for fees, payments, and refunds with formatted currency display.
    • Enhanced customization capabilities for total rows with configurable styling and label options.
    • Expanded internationalization support for payment and refund-related content.
  • Chores

    • Bumped version to 5.0.17-beta.4.

@santipalenque santipalenque requested a review from smarcet April 28, 2026 16:57
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

📝 Walkthrough

Walkthrough

Package version bumped to 5.0.17-beta.4. DashboardCard component replaced with three new card variants (InlineCard, ListCard, TableCard). Three new table row components added (FeeRow, PaymentRow, RefundRow). Supporting utilities, exports, tests, i18n strings, and webpack configuration updated accordingly.

Changes

Cohort / File(s) Summary
Version Bumping
package.json
Package version updated from 5.0.15 to 5.0.17-beta.4.
Component Exports
src/components/index.js
Barrel export updated: removed MuiDashboardCard, added MuiInlineCard, MuiListCard, MuiTableCard; added table row exports MuiFeeRow, MuiPaymentRow, MuiRefundRow.
Card Component Removal
src/components/mui/DashboardCard/index.js, src/components/mui/__tests__/dashboard-card.test.js
DashboardCard component and its test suite fully removed.
New Card Components
src/components/mui/cards/InlineCard/index.js, src/components/mui/cards/ListCard/index.js, src/components/mui/cards/TableCard/index.js
Added three new card component variants supporting configurable title and rows/columns display patterns.
Card Component Utilities
src/components/mui/cards/components/Heading.js, src/components/mui/cards/components/Value.js
Added shared Typography-based utility components for consistent label/value rendering within cards.
Card Module Exports
src/components/mui/cards/index.js
New barrel module aggregating exports for InlineCard, ListCard, and TableCard.
New Table Row Components
src/components/mui/table/extra-rows/FeeRow.jsx, src/components/mui/table/extra-rows/PaymentRow.jsx, src/components/mui/table/extra-rows/RefundRow.jsx
Added three new table row components for rendering fee, payment, and refund data with configurable spacing.
Table Row Updates
src/components/mui/table/extra-rows/TotalRow.jsx, src/components/mui/table/extra-rows/index.js
TotalRow enhanced with rowSx and label props; new row components exported from module barrel.
Internationalization
src/i18n/en.json
Added translation keys for payment, refund, and fee labels under mui_table section.
Utility Constants
src/utils/constants.js
Added DATE_FORMAT and DATETIME_FORMAT export constants.
Build Configuration
webpack.common.js
Webpack entry points updated: replaced components/mui/dashboard-card with components/mui/cards and individual card variant entries (inline-card, list-card, table-card).
Component Tests
src/components/mui/__tests__/fee-row.test.js, src/components/mui/__tests__/payment-row.test.js, src/components/mui/__tests__/refund-row.test.js, src/components/mui/__tests__/table-card.test.js
Added comprehensive test suites for new row and card components verifying rendering, data formatting, and edge cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • smarcet

Poem

🐰 Three cards hop in to replace the old friend,
Fees and payments in table rows blend,
Constants and translations aligned just right,
New components render in Material light! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Feature/add order details components' directly summarizes the main changeset: adding new card components (InlineCard, ListCard, TableCard), new table row components (FeeRow, PaymentRow, RefundRow), and removing the legacy DashboardCard. The title accurately captures the primary intent.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/add-order-details-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
Copy Markdown

@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 (4)
src/components/mui/cards/TableCard/index.js (1)

37-50: Prefer stable keys over index-derived keys for mapped items.

On Line 39, Line 45, and Line 49, index-based keys can cause reconciliation issues when data order changes. Use stable data keys where possible.

💡 Suggested fix
-          {columns.map((col, i) => (
+          {columns.map((col) => (
             // eslint-disable-next-line react/no-array-index-key
-            <Heading key={`col-${col.key}-${i}`}>{col.label}</Heading>
+            <Heading key={`col-${col.key}`}>{col.label}</Heading>
           ))}
@@
-        {rows.map((row, i) => (
+        {rows.map((row, i) => (
           // eslint-disable-next-line react/no-array-index-key
-          <React.Fragment key={`row-${i}`}>
+          <React.Fragment key={row.id ?? row.ref ?? `row-${i}`}>
@@
-              {columns.map((col, j) => (
+              {columns.map((col) => (
                 // eslint-disable-next-line react/no-array-index-key
-                <Value key={`col-val-${col.key}-${j}`}>{row[col.key]}</Value>
+                <Value key={`col-val-${col.key}`}>{row[col.key]}</Value>
               ))}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/cards/TableCard/index.js` around lines 37 - 50, Replace
the index-derived keys used in the mapped JSX for columns and rows with stable
unique identifiers: use col.key alone for column Heading and Value keys, and use
a stable unique property from each row (e.g., row.id or another unique field)
for the row React.Fragment key (e.g., key={`row-${row.id}`}) and for any
per-cell keys that need to combine row and column (e.g.,
key={`cell-${row.id}-${col.key}`}); update the mappings in the TableCard
component (the columns.map, rows.map, and inner columns.map) to remove the
index-based keys and the eslint-disable comments.
src/components/mui/__tests__/refund-row.test.js (1)

37-70: Add coverage for colGap and trailing cell rendering.

The suite currently validates content, but not the dynamic spacer/trailing columns. A focused assertion on rendered <td> count would lock down this new behavior.

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

In `@src/components/mui/__tests__/refund-row.test.js` around lines 37 - 70, The
tests for RefundRow (use renderInTable to mount) are missing assertions that the
dynamic spacer/trailing cells are rendered; update the suite to, after rendering
via renderInTable({ refund: ... }), assert the number of <td> elements
(container.querySelectorAll("td")) matches the expected count and also assert
the existence of the spacer and trailing cells by selecting their identifying
classes or attributes (e.g., a cell with class/name colGap and a cell with
class/name trailing) so colGap and trailing cell rendering is covered.
src/components/mui/__tests__/fee-row.test.js (1)

37-62: Consider adding coverage for colGap and trailing layout behavior.

The suite is good, but one focused test for gap/trailing cell counts would lock in the new layout contract.

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

In `@src/components/mui/__tests__/fee-row.test.js` around lines 37 - 62, Add a
focused test in the FeeRow suite to assert the new layout contract for colGap
and trailing: render the component via renderInTable with a fee and with colGap
and trailing props set (e.g., colGap: X, trailing: Y) and assert the expected
number of cells/columns and spacing behavior by querying
container.querySelectorAll("td") or specific test ids and checking computed
styles or class names; update or add tests named like "renders correct cells for
colGap and trailing" referencing renderInTable and FeeRow so the suite verifies
both cell count and the trailing-gap layout.
src/components/mui/table/extra-rows/TotalRow.jsx (1)

21-21: Use nullish coalescing for label prop for consistency with best practices.

The current || operator treats "" as absent, while ?? only treats null and undefined as absent. Although no callers currently pass empty strings, using ?? is the more precise operator for this pattern.

♻️ Proposed change
-  const totalLabel = label || T.translate("mui_table.total");
+  const totalLabel = label ?? T.translate("mui_table.total");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/table/extra-rows/TotalRow.jsx` at line 21, Replace the
fallback using the logical OR with nullish coalescing for the label prop: update
the expression that defines totalLabel (currently using `label ||
T.translate("mui_table.total")`) to use `??` so it only falls back when `label`
is null or undefined (i.e., `totalLabel = label ??
T.translate("mui_table.total")`), keeping the rest of the component and
translation call unchanged.
🤖 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/components/mui/__tests__/payment-row.test.js`:
- Around line 28-29: The inline comment for the PAYMENT_TIMESTAMP constant is
incorrect; update the comment that currently reads "2026-01-15 00:00:00 UTC" to
the correct date "2025-01-15 00:00:00 UTC" so it matches the numeric value
1736899200 in the PAYMENT_TIMESTAMP constant used in the payment-row.test.js
file.

In `@src/components/mui/cards/ListCard/index.js`:
- Around line 29-33: The ListItem key using row.id ?? row.label can produce
duplicate keys when ids are missing; fix by ensuring the data source always
provides row.id where possible, and when a fallback is necessary use a stable,
namespaced fallback key (e.g., include the label plus the index like
"row-{label}-{i}") and mirror the repo pattern by adding a single-line eslint
disable for react/no-array-index-key above the ListItem key; update the mapping
that renders rows (the rows array/map and the ListItem JSX) to use this
namespaced fallback so keys are unique and consistent.

In `@src/components/mui/table/extra-rows/FeeRow.jsx`:
- Around line 21-47: In FeeRow, guard the colGap and trailing props before
calling Array(colGap)/Array(trailing): ensure colGap and trailing are normalized
to safe non-negative integers (e.g., coerce with parseInt/Number and fall back
to 0, or use Math.max(0, Math.floor(value))) at the top of the FeeRow component
so the [...Array(...)] maps never receive negative or non-integer lengths;
update references in the mapping expressions (the two [...Array(colGap)] and
[...Array(trailing)] usages) to use these sanitized variables.

In `@src/components/mui/table/extra-rows/PaymentRow.jsx`:
- Around line 23-63: PaymentRow currently constructs arrays with Array(colGap)
and Array(trailing) and calls moment(payment.created...) without validating
inputs; add defensive validation: coerce and clamp colGap and trailing at the
top of PaymentRow (e.g. let safeColGap = Math.max(0, Number.isFinite(colGap) ?
Math.floor(colGap) : 0) and same for trailing) and replace
Array(colGap)/Array(trailing) usage with Array(safeColGap)/Array(safeTrailing);
also validate payment.created before using moment (e.g. const ts =
Number.isFinite(payment?.created) ? payment.created * MILLISECONDS_IN_SECOND :
null and render a safe fallback when ts is null); apply the same validation
pattern to FeeRow, RefundRow, and TotalRow for their colGap/trailing and any
timestamp usage to avoid RangeError and invalid date formatting.

In `@src/components/mui/table/extra-rows/RefundRow.jsx`:
- Around line 46-61: The RefundRow component should sanitize its colGap and
trailing props at entry to avoid RangeError from Array(colGap)/Array(trailing);
inside the RefundRow function/component, coerce each prop to a safe non-negative
integer (e.g., let safeColGap = Math.max(0, Math.floor(Number(colGap) || 0)) and
let safeTrailing = Math.max(0, Math.floor(Number(trailing) || 0))) and then use
safeColGap and safeTrailing in the two [...Array(...)] map calls; this prevents
negative, non-integer, or non-numeric inputs from causing runtime crashes while
preserving the existing rendering logic (refer to the RefundRow component and
its uses of colGap/trailing).

---

Nitpick comments:
In `@src/components/mui/__tests__/fee-row.test.js`:
- Around line 37-62: Add a focused test in the FeeRow suite to assert the new
layout contract for colGap and trailing: render the component via renderInTable
with a fee and with colGap and trailing props set (e.g., colGap: X, trailing: Y)
and assert the expected number of cells/columns and spacing behavior by querying
container.querySelectorAll("td") or specific test ids and checking computed
styles or class names; update or add tests named like "renders correct cells for
colGap and trailing" referencing renderInTable and FeeRow so the suite verifies
both cell count and the trailing-gap layout.

In `@src/components/mui/__tests__/refund-row.test.js`:
- Around line 37-70: The tests for RefundRow (use renderInTable to mount) are
missing assertions that the dynamic spacer/trailing cells are rendered; update
the suite to, after rendering via renderInTable({ refund: ... }), assert the
number of <td> elements (container.querySelectorAll("td")) matches the expected
count and also assert the existence of the spacer and trailing cells by
selecting their identifying classes or attributes (e.g., a cell with class/name
colGap and a cell with class/name trailing) so colGap and trailing cell
rendering is covered.

In `@src/components/mui/cards/TableCard/index.js`:
- Around line 37-50: Replace the index-derived keys used in the mapped JSX for
columns and rows with stable unique identifiers: use col.key alone for column
Heading and Value keys, and use a stable unique property from each row (e.g.,
row.id or another unique field) for the row React.Fragment key (e.g.,
key={`row-${row.id}`}) and for any per-cell keys that need to combine row and
column (e.g., key={`cell-${row.id}-${col.key}`}); update the mappings in the
TableCard component (the columns.map, rows.map, and inner columns.map) to remove
the index-based keys and the eslint-disable comments.

In `@src/components/mui/table/extra-rows/TotalRow.jsx`:
- Line 21: Replace the fallback using the logical OR with nullish coalescing for
the label prop: update the expression that defines totalLabel (currently using
`label || T.translate("mui_table.total")`) to use `??` so it only falls back
when `label` is null or undefined (i.e., `totalLabel = label ??
T.translate("mui_table.total")`), keeping the rest of the component and
translation call unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a9c2ca24-de37-44d7-ba35-e2cae99cf15e

📥 Commits

Reviewing files that changed from the base of the PR and between 373c59f and 705649a.

📒 Files selected for processing (22)
  • package.json
  • src/components/index.js
  • src/components/mui/DashboardCard/index.js
  • src/components/mui/__tests__/dashboard-card.test.js
  • src/components/mui/__tests__/fee-row.test.js
  • src/components/mui/__tests__/payment-row.test.js
  • src/components/mui/__tests__/refund-row.test.js
  • src/components/mui/__tests__/table-card.test.js
  • src/components/mui/cards/InlineCard/index.js
  • src/components/mui/cards/ListCard/index.js
  • src/components/mui/cards/TableCard/index.js
  • src/components/mui/cards/components/Heading.js
  • src/components/mui/cards/components/Value.js
  • src/components/mui/cards/index.js
  • src/components/mui/table/extra-rows/FeeRow.jsx
  • src/components/mui/table/extra-rows/PaymentRow.jsx
  • src/components/mui/table/extra-rows/RefundRow.jsx
  • src/components/mui/table/extra-rows/TotalRow.jsx
  • src/components/mui/table/extra-rows/index.js
  • src/i18n/en.json
  • src/utils/constants.js
  • webpack.common.js
💤 Files with no reviewable changes (2)
  • src/components/mui/tests/dashboard-card.test.js
  • src/components/mui/DashboardCard/index.js

Comment on lines +28 to +29
// 2026-01-15 00:00:00 UTC in seconds
const PAYMENT_TIMESTAMP = 1736899200;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix the timestamp comment to match the constant value.

1736899200 is 2025-01-15 00:00:00 UTC, not 2026. The assertion logic is fine, but this comment is misleading.

Suggested patch
-// 2026-01-15 00:00:00 UTC in seconds
+// 2025-01-15 00:00:00 UTC in seconds
 const PAYMENT_TIMESTAMP = 1736899200;
📝 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
// 2026-01-15 00:00:00 UTC in seconds
const PAYMENT_TIMESTAMP = 1736899200;
// 2025-01-15 00:00:00 UTC in seconds
const PAYMENT_TIMESTAMP = 1736899200;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/__tests__/payment-row.test.js` around lines 28 - 29, The
inline comment for the PAYMENT_TIMESTAMP constant is incorrect; update the
comment that currently reads "2026-01-15 00:00:00 UTC" to the correct date
"2025-01-15 00:00:00 UTC" so it matches the numeric value 1736899200 in the
PAYMENT_TIMESTAMP constant used in the payment-row.test.js file.

Comment on lines +29 to +33
{(rows ?? []).map((row, i) => (
<ListItem
key={row.id ?? row.label}
divider={i < (rows ?? []).length - 1}
sx={{ display: "flex", height: 50 }}
Copy link
Copy Markdown

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/components/mui/cards/ListCard/index.js

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 1856


🏁 Script executed:

# Check for prop types definition
fd -t f "ListCard" --exec grep -l "propTypes\|interface ListCard\|type ListCard" {} \;

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 66


🏁 Script executed:

# Search for ListCard usage in the codebase
rg "ListCard" --type jsx --type js --type tsx --type ts -B 2 -A 5

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 112


🏁 Script executed:

# Search for ListCard usage more broadly
rg "ListCard" -B 2 -A 5

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 2575


🏁 Script executed:

# Also check if there are TypeScript definitions or interfaces
fd -t f "\\.tsx?$" | xargs grep -l "ListCard" 2>/dev/null | head -20

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 66


🏁 Script executed:

# Find all files that import or use ListCard/MuiListCard
rg "import.*ListCard|MuiListCard" -B 2 -A 10

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 1105


🏁 Script executed:

# Also check if there's any test file or documentation
fd -t f "ListCard" -o "list-card"

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 222


🏁 Script executed:

# Look for README or documentation about components
find . -name "README*" -o -name "CONTRIBUTING*" | head -10

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 66


🏁 Script executed:

# Check similar cards to see if they have same pattern
cat -n src/components/mui/cards/InlineCard/index.js 2>/dev/null | head -50

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 2087


🏁 Script executed:

# Check if there's a shared pattern in other list/table implementations
rg "\.map.*key=" src/components --type js -A 1 -B 1

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 66


🏁 Script executed:

# Check TableCard for comparison
cat -n src/components/mui/cards/TableCard/index.js 2>/dev/null | head -80 | tail -50

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 1925


🏁 Script executed:

# Search for react/no-array-index-key eslint disable comments
rg "no-array-index-key" -B 2 -A 2

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 4969


Duplicate keys possible when row.id is missing, but suggested fix introduces worse anti-pattern.

The concern about row.id ?? row.label is valid—if multiple rows share the same label, React cannot distinguish them, causing unstable reconciliation. However, the suggested fix using ${row.label}-${i} introduces array index keys, which is a React anti-pattern that causes reordering bugs and contradicts the codebase's own approach (see InlineCard and TableCard, which explicitly disable react/no-array-index-key when index-based keys are necessary).

Better alternatives:

  • Ensure row.id is always populated in the data source (most reliable)
  • If fallback is needed, follow the codebase pattern: key={row-${row.label}-${i}} with // eslint-disable-next-line react/no-array-index-key
  • Or implement a stable fallback: key={row.id ?? ${row.label}-${indexOf}} where indexOf is a stable identifier from data context
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/cards/ListCard/index.js` around lines 29 - 33, The
ListItem key using row.id ?? row.label can produce duplicate keys when ids are
missing; fix by ensuring the data source always provides row.id where possible,
and when a fallback is necessary use a stable, namespaced fallback key (e.g.,
include the label plus the index like "row-{label}-{i}") and mirror the repo
pattern by adding a single-line eslint disable for react/no-array-index-key
above the ListItem key; update the mapping that renders rows (the rows array/map
and the ListItem JSX) to use this namespaced fallback so keys are unique and
consistent.

Comment on lines +21 to +47
const FeeRow = ({ fee, colGap = 3, trailing = 0 }) => {
if (!fee) return null;

return (
<TableRow>
<TableCell>{T.translate("mui_table.payfee")}</TableCell>
<TableCell>
<Typography variant="body2" sx={{ fontWeight: 500 }}>
{fee.title}
</Typography>
</TableCell>
{[...Array(colGap)].map((_, i) => (
// eslint-disable-next-line react/no-array-index-key
<TableCell key={`fee-col-gap-${i}`} />
))}
<TableCell>
<Typography
variant="body2"
sx={{ color: "success.main", fontWeight: 500 }}
>
{currencyAmountFromCents(fee.amount)}
</Typography>
</TableCell>
{[...Array(trailing)].map((_, i) => (
// eslint-disable-next-line react/no-array-index-key
<TableCell key={`fee-trailing-col-${i}`} sx={{ width: 40 }} />
))}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard colGap/trailing before using Array(...).

Array(colGap)/Array(trailing) can throw for invalid values (e.g., negative or non-integer). Consider normalizing these props to safe non-negative integers.

Suggested patch
 const FeeRow = ({ fee, colGap = 3, trailing = 0 }) => {
   if (!fee) return null;
+  const safeColGap = Number.isInteger(colGap) && colGap > 0 ? colGap : 0;
+  const safeTrailing = Number.isInteger(trailing) && trailing > 0 ? trailing : 0;
 
   return (
     <TableRow>
@@
-      {[...Array(colGap)].map((_, i) => (
+      {[...Array(safeColGap)].map((_, i) => (
         // eslint-disable-next-line react/no-array-index-key
         <TableCell key={`fee-col-gap-${i}`} />
       ))}
@@
-      {[...Array(trailing)].map((_, i) => (
+      {[...Array(safeTrailing)].map((_, i) => (
         // eslint-disable-next-line react/no-array-index-key
         <TableCell key={`fee-trailing-col-${i}`} sx={{ width: 40 }} />
       ))}
📝 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 FeeRow = ({ fee, colGap = 3, trailing = 0 }) => {
if (!fee) return null;
return (
<TableRow>
<TableCell>{T.translate("mui_table.payfee")}</TableCell>
<TableCell>
<Typography variant="body2" sx={{ fontWeight: 500 }}>
{fee.title}
</Typography>
</TableCell>
{[...Array(colGap)].map((_, i) => (
// eslint-disable-next-line react/no-array-index-key
<TableCell key={`fee-col-gap-${i}`} />
))}
<TableCell>
<Typography
variant="body2"
sx={{ color: "success.main", fontWeight: 500 }}
>
{currencyAmountFromCents(fee.amount)}
</Typography>
</TableCell>
{[...Array(trailing)].map((_, i) => (
// eslint-disable-next-line react/no-array-index-key
<TableCell key={`fee-trailing-col-${i}`} sx={{ width: 40 }} />
))}
const FeeRow = ({ fee, colGap = 3, trailing = 0 }) => {
if (!fee) return null;
const safeColGap = Number.isInteger(colGap) && colGap > 0 ? colGap : 0;
const safeTrailing = Number.isInteger(trailing) && trailing > 0 ? trailing : 0;
return (
<TableRow>
<TableCell>{T.translate("mui_table.payfee")}</TableCell>
<TableCell>
<Typography variant="body2" sx={{ fontWeight: 500 }}>
{fee.title}
</Typography>
</TableCell>
{[...Array(safeColGap)].map((_, i) => (
// eslint-disable-next-line react/no-array-index-key
<TableCell key={`fee-col-gap-${i}`} />
))}
<TableCell>
<Typography
variant="body2"
sx={{ color: "success.main", fontWeight: 500 }}
>
{currencyAmountFromCents(fee.amount)}
</Typography>
</TableCell>
{[...Array(safeTrailing)].map((_, i) => (
// eslint-disable-next-line react/no-array-index-key
<TableCell key={`fee-trailing-col-${i}`} sx={{ width: 40 }} />
))}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/table/extra-rows/FeeRow.jsx` around lines 21 - 47, In
FeeRow, guard the colGap and trailing props before calling
Array(colGap)/Array(trailing): ensure colGap and trailing are normalized to safe
non-negative integers (e.g., coerce with parseInt/Number and fall back to 0, or
use Math.max(0, Math.floor(value))) at the top of the FeeRow component so the
[...Array(...)] maps never receive negative or non-integer lengths; update
references in the mapping expressions (the two [...Array(colGap)] and
[...Array(trailing)] usages) to use these sanitized variables.

Comment on lines +23 to +63
const PaymentRow = ({ payment, colGap = 1, trailing = 0 }) => {

if (!payment) return null;

return (
<TableRow sx={{backgroundColor: "#2E7D3214"}}>
<TableCell>{T.translate("mui_table.pay")}</TableCell>
<TableCell>
<Typography
variant="body2"
sx={{ color: "success.main", fontWeight: 500 }}
>
{T.translate("mui_table.payment")}
</Typography>
</TableCell>
<TableCell>
<Typography variant="body2" sx={{ color: "text.secondary" }}>
{T.translate("mui_table.paid_via")} {payment.method}
</Typography>
</TableCell>
<TableCell>
<Typography variant="body2" sx={{ color: "text.secondary" }}>
{moment(payment.created * MILLISECONDS_IN_SECOND).format(DATETIME_FORMAT)}
</Typography>
</TableCell>
{[...Array(colGap)].map((_, i) => (
// eslint-disable-next-line react/no-array-index-key
<TableCell key={`pay-col-gap-${i}`} />
))}
<TableCell>
<Typography
variant="body2"
sx={{ color: "success.main", fontWeight: 500 }}
>
-{currencyAmountFromCents(payment.amount)}
</Typography>
</TableCell>
{[...Array(trailing)].map((_, i) => (
// eslint-disable-next-line react/no-array-index-key
<TableCell key={`pay-trailing-col-${i}`} sx={{ width: 40 }} />
))}
Copy link
Copy Markdown

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:

#!/bin/bash
# Inspect PaymentRow callsites and passed props to confirm whether created/colGap/trailing are always sanitized.
rg -nP --type=js --type=jsx -C3 '<(Mui)?PaymentRow\b'
rg -nP --type=js --type=jsx -C3 '\bcolGap\s*=|\btrailing\s*=|\bcreated\b'

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 140


🏁 Script executed:

# Search for PaymentRow callsites and prop usage without file type restrictions
rg -n 'PaymentRow' --type js -C3 .

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 3941


🏁 Script executed:

# Find the PaymentRow component file to confirm it exists
find . -name "PaymentRow.jsx" -o -name "PaymentRow.js"

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 137


🏁 Script executed:

# Search for how colGap and trailing are passed when calling PaymentRow
rg -n 'colGap|trailing' --type js -C2 .

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 7070


🏁 Script executed:

cat -n ./src/components/mui/__tests__/payment-row.test.js

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 2941


🏁 Script executed:

# Search for actual usage of PaymentRow or MuiPaymentRow in the codebase
rg -n 'MuiPaymentRow|<PaymentRow' --type js -C3 .

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 1416


🏁 Script executed:

# Check where payment objects are created/passed to understand the data flow
rg -n 'payment\s*[:=]' --type js -B2 -A2 . | head -100

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 2098


🏁 Script executed:

# Search for actual usage in app components
rg -n 'MuiPaymentRow' --type js -C3 .

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 932


🏁 Script executed:

# Look for places that might construct payment objects
rg -n 'payment.*created|created.*payment' --type js -B2 -A2 . | head -80

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 2595


🏁 Script executed:

# Test Array() behavior with various invalid inputs
node -e "
console.log('Array(1):', Array(1));
console.log('Array(0):', Array(0));
console.log('Array(-1):', Array(-1));
console.log('Array(NaN):', Array(NaN));
console.log('Array(Infinity):', Array(Infinity));
console.log('Array({}):', Array({}));
try { console.log('[...Array(-1)]:', [...Array(-1)]); } catch(e) { console.log('Error:', e.message); }
"

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 652


🏁 Script executed:

# Check test coverage for other row components with similar pattern
cat -n ./src/components/mui/__tests__/fee-row.test.js 2>/dev/null || echo "File not found"

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 2601


🏁 Script executed:

cat -n ./src/components/mui/__tests__/refund-row.test.js 2>/dev/null || echo "File not found"

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 3059


🏁 Script executed:

# Search for where colGap/trailing are actually passed in the component tree
rg -n 'colGap\s*=' --type js -B3 -A1 . | grep -v test | head -60

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 1507


🏁 Script executed:

# Check payment data source/validation
rg -n 'payment' --type js | grep -i 'schema\|validate\|type\|interface' | head -30

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 66


Add defensive validation for numeric props to prevent runtime crashes.

Array(colGap) and Array(trailing) will throw a RangeError: Invalid array length if passed negative or non-finite values, breaking rendering. payment.created is also used without validation, risking invalid date formatting if the value is null or malformed. Sanitizing these inputs prevents edge-case crashes:

  • Validate colGap and trailing with Math.max(0, Number.isFinite(...) ? Math.floor(...) : 0)
  • Validate payment.created with Number.isFinite() before passing to moment

This pattern should also be applied to similar components: FeeRow, RefundRow, and TotalRow use the same unsafe Array() pattern.

Suggested fix
 const PaymentRow = ({ payment, colGap = 1, trailing = 0 }) => {
 
   if (!payment) return null;
+  const safeColGap = Math.max(0, Number.isFinite(colGap) ? Math.floor(colGap) : 0);
+  const safeTrailing = Math.max(0, Number.isFinite(trailing) ? Math.floor(trailing) : 0);
+  const createdAt = Number(payment.created);
+  const createdLabel = Number.isFinite(createdAt)
+    ? moment.unix(createdAt).format(DATETIME_FORMAT)
+    : "";
 
   return (
     <TableRow sx={{backgroundColor: "#2E7D3214"}}>
@@
       <TableCell>
         <Typography variant="body2" sx={{ color: "text.secondary" }}>
-          {moment(payment.created * MILLISECONDS_IN_SECOND).format(DATETIME_FORMAT)}
+          {createdLabel}
         </Typography>
       </TableCell>
-      {[...Array(colGap)].map((_, i) => (
+      {[...Array(safeColGap)].map((_, i) => (
         // eslint-disable-next-line react/no-array-index-key
         <TableCell key={`pay-col-gap-${i}`} />
       ))}
@@
-      {[...Array(trailing)].map((_, i) => (
+      {[...Array(safeTrailing)].map((_, i) => (
         // eslint-disable-next-line react/no-array-index-key
         <TableCell key={`pay-trailing-col-${i}`} sx={{ width: 40 }} />
       ))}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/table/extra-rows/PaymentRow.jsx` around lines 23 - 63,
PaymentRow currently constructs arrays with Array(colGap) and Array(trailing)
and calls moment(payment.created...) without validating inputs; add defensive
validation: coerce and clamp colGap and trailing at the top of PaymentRow (e.g.
let safeColGap = Math.max(0, Number.isFinite(colGap) ? Math.floor(colGap) : 0)
and same for trailing) and replace Array(colGap)/Array(trailing) usage with
Array(safeColGap)/Array(safeTrailing); also validate payment.created before
using moment (e.g. const ts = Number.isFinite(payment?.created) ?
payment.created * MILLISECONDS_IN_SECOND : null and render a safe fallback when
ts is null); apply the same validation pattern to FeeRow, RefundRow, and
TotalRow for their colGap/trailing and any timestamp usage to avoid RangeError
and invalid date formatting.

Comment on lines +46 to +61
{[...Array(colGap)].map((_, i) => (
// eslint-disable-next-line react/no-array-index-key
<TableCell key={`ref-col-gap-${i}`} />
))}
<TableCell>
<Typography
variant="body2"
sx={{ color: "warning.main", fontWeight: 500 }}
>
-{currencyAmountFromCents(refund.amount)}
</Typography>
</TableCell>
{[...Array(trailing)].map((_, i) => (
// eslint-disable-next-line react/no-array-index-key
<TableCell key={`ref-trailing-col-${i}`} sx={{ width: 40 }} />
))}
Copy link
Copy Markdown

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:

find . -name "RefundRow.jsx" -o -name "RefundRow.js" -o -name "RefundRow.tsx"

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 136


🏁 Script executed:

fd -t f "RefundRow\.(jsx|js|tsx|ts)$"

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 134


🏁 Script executed:

cat -n src/components/mui/table/extra-rows/RefundRow.jsx

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 2792


🏁 Script executed:

rg "RefundRow" --type jsx --type js --type tsx --type ts -A 3 -B 1

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 112


🏁 Script executed:

rg "RefundRow" -A 3 -B 1

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 2521


🏁 Script executed:

cat -n src/components/mui/__tests__/refund-row.test.js

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 3059


🏁 Script executed:

rg "RefundRow" --no-heading -B 2 -A 5

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 3551


🏁 Script executed:

rg "MuiRefundRow|<RefundRow" -B 2 -A 2

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 1029


Add input validation for colGap and trailing props to prevent runtime crashes.

On lines 46 and 58, Array(colGap) and Array(trailing) can throw RangeError if values are negative, non-integers, or invalid. Although defaults are safe (1 and 0), callers can pass invalid values. Add validation to normalize these props at component entry.

Suggested fix
 const RefundRow = ({ refund, colGap = 1, trailing = 0 }) => {
 
   if (!refund) return null;
+  const safeColGap = Number.isInteger(colGap) && colGap > 0 ? colGap : 0;
+  const safeTrailing = Number.isInteger(trailing) && trailing > 0 ? trailing : 0;
 
   return (
       {[...Array(safeColGap)].map((_, i) => (
           <TableCell key={`ref-col-gap-${i}`} />
       ))}
-      {[...Array(trailing)].map((_, i) => (
+      {[...Array(safeTrailing)].map((_, i) => (
           <TableCell key={`ref-trailing-col-${i}`} sx={{ width: 40 }} />
       ))}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/table/extra-rows/RefundRow.jsx` around lines 46 - 61, The
RefundRow component should sanitize its colGap and trailing props at entry to
avoid RangeError from Array(colGap)/Array(trailing); inside the RefundRow
function/component, coerce each prop to a safe non-negative integer (e.g., let
safeColGap = Math.max(0, Math.floor(Number(colGap) || 0)) and let safeTrailing =
Math.max(0, Math.floor(Number(trailing) || 0))) and then use safeColGap and
safeTrailing in the two [...Array(...)] map calls; this prevents negative,
non-integer, or non-numeric inputs from causing runtime crashes while preserving
the existing rendering logic (refer to the RefundRow component and its uses of
colGap/trailing).

Copy link
Copy Markdown
Collaborator

@smarcet smarcet left a comment

Choose a reason for hiding this comment

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

LGTM

@smarcet smarcet merged commit e478081 into main May 4, 2026
5 checks passed
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.

2 participants