Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "openstack-uicore-foundation",
"version": "5.0.15-beta.2",
"version": "5.0.13-beta.3",
"description": "ui reactjs components for openstack marketing site",
"main": "lib/openstack-uicore-foundation.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export {default as MuiShowConfirmDialog} from './mui/showConfirmDialog'
export {default as MuiSponsorAddonSelect} from './mui/sponsor-addon-select'
export {default as MuiSummitAddonSelect} from './mui/summit-addon-select'
export {default as MuiSummitsDropdown} from './mui/summits-dropdown'
export {default as MuiFormItemTable} from './mui/FormItemTable'
export {default as MuiFormItemTable, getCurrentApplicableRate, isItemAvailable, GlobalQuantityField, ItemTableField, UnderlyingAlertNote} from './mui/FormItemTable'
export {default as MuiItemSettingsModal} from './mui/ItemSettingsModal'
export {default as MuiNotesModal} from './mui/NotesModal'
export {default as MuiSnackbarNotification} from './mui/SnackbarNotification'
Expand Down
15 changes: 15 additions & 0 deletions src/components/mui/FormItemTable/__tests__/FormItemTable.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,21 @@ jest.mock("../../formik-inputs/mui-formik-select", () => ({
)
}));

jest.mock("../../formik-inputs/mui-formik-select-v2", () => ({
__esModule: true,
default: ({ name, label, options }) => (
<select data-testid={`select-${name}`} name={name}>
<option value="">{label}</option>
{options &&
options.map((opt) => (
<option key={opt.value} value={opt.value}>
{opt.label}
</option>
))}
</select>
)
}));

jest.mock("../../formik-inputs/mui-formik-checkbox", () => ({
__esModule: true,
default: ({ name, label }) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ jest.mock("../../formik-inputs/mui-formik-select", () => {
};
});

jest.mock("../../formik-inputs/mui-formik-select-v2", () => {
const React = require("react");
return {
__esModule: true,
default: ({ name }) => <div data-testid="select" data-name={name} />
};
});
Comment on lines +83 to +89

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

Duplicate data-testid="select" collides with the existing mock.

Both mui-formik-select (Line 76) and mui-formik-select-v2 (Line 87) now render data-testid="select". Any test that renders both (or queries with getAllByTestId) becomes ambiguous, and the ComboBox test at Line 138 no longer clearly targets v2. Use a distinct id such as "select-v2" and update the corresponding assertion/title.

Proposed fix
 jest.mock("../../formik-inputs/mui-formik-select-v2", () => {
   const React = require("react");
   return {
     __esModule: true,
-    default: ({ name }) => <div data-testid="select" data-name={name} />
+    default: ({ name }) => <div data-testid="select-v2" data-name={name} />
   };
 });

And update the ComboBox test:

-  test("renders MuiFormikSelect for ComboBox type", () => {
+  test("renders MuiFormikSelectV2 for ComboBox type", () => {
     renderField({ type: "ComboBox" });
-    expect(screen.getByTestId("select")).toBeInTheDocument();
+    expect(screen.getByTestId("select-v2")).toBeInTheDocument();
   });
📝 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
jest.mock("../../formik-inputs/mui-formik-select-v2", () => {
const React = require("react");
return {
__esModule: true,
default: ({ name }) => <div data-testid="select" data-name={name} />
};
});
jest.mock("../../formik-inputs/mui-formik-select-v2", () => {
const React = require("react");
return {
__esModule: true,
default: ({ name }) => <div data-testid="select-v2" data-name={name} />
};
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/__tests__/ItemTableField.test.js` around
lines 83 - 89, The mock for "mui-formik-select-v2" is using the same data-testid
as the other select mock, causing ambiguous queries; update the jest.mock for
mui-formik-select-v2 (the default mock component defined in the jest.mock call
for "mui-formik-select-v2") to render a unique attribute such as
data-testid="select-v2" (and keep data-name the same), then update the ComboBox
test assertion/title that expects the v2 select (the test referenced as the
ComboBox test) to query for "select-v2" (and rename the test title if it refers
to v2) so queries like getByTestId/getAllByTestId unambiguously target the v2
mock.


import React from "react";
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
Expand Down
17 changes: 7 additions & 10 deletions src/components/mui/FormItemTable/components/ItemTableField.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@
* */

import React from "react";
import { MenuItem } from "@mui/material";
import MuiFormikCheckbox from "../../formik-inputs/mui-formik-checkbox";
import MuiFormikDropdownCheckbox from "../../formik-inputs/mui-formik-dropdown-checkbox";
import MuiFormikDropdownRadio from "../../formik-inputs/mui-formik-dropdown-radio";
import MuiFormikDatepicker from "../../formik-inputs/mui-formik-datepicker";
import MuiFormikTimepicker from "../../formik-inputs/mui-formik-timepicker";
import MuiFormikTextField from "../../formik-inputs/mui-formik-textfield";
import MuiFormikSelect from "../../formik-inputs/mui-formik-select";
import MuiFormikSelectV2 from "../../formik-inputs/mui-formik-select-v2";

const ItemTableField = ({
rowId,
Expand All @@ -33,7 +32,7 @@ const ItemTableField = ({

switch (field.type) {
case "CheckBox":
return <MuiFormikCheckbox {...commonProps} />;
return <MuiFormikCheckbox {...commonProps} size="small" />;
case "CheckBoxList":
return (
<MuiFormikDropdownCheckbox
Expand Down Expand Up @@ -73,13 +72,11 @@ const ItemTableField = ({
);
case "ComboBox":
return (
<MuiFormikSelect {...commonProps} size="small">
{field.values.map((v) => (
<MenuItem key={`ddopt-${v.id}`} value={v.id}>
{v.value}
</MenuItem>
))}
</MuiFormikSelect>
<MuiFormikSelectV2
{...commonProps}
size="small"
options={field.values.map((v) => ({ value: v.id, label: v.value }))}
/>
Comment on lines +75 to +79

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

🌐 Web query:

For MUI v6 Select with displayEmpty and InputLabel, does the label need to be forced shrink to avoid overlap with the empty placeholder?

💡 Result:

Yes, in MUI v6, when using Select with displayEmpty={true} and an InputLabel, the label needs to be forced to shrink (via shrink={true} on InputLabel) to avoid overlapping with the empty placeholder value. The official Select API documentation explicitly warns: "When using this prop, make sure the label doesn't overlap with the empty displayed value. The label should either be hidden or forced to a shrunk state." For outlined variant, you may also need notched={true} on the Select to properly notch the border.

Citations:


🏁 Script executed:

# First, find and read the ItemTableField.js file around lines 75-79
fd -t f "ItemTableField.js" | head -5

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 145


🏁 Script executed:

# Also search for the mui-formik-select-v2.js file
fd -t f "mui-formik-select-v2.js" | head -5

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 140


🏁 Script executed:

# Check for MUI version in package.json
fd -t f "package.json" -x grep -l "\"@mui" {} \;

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 98


🏁 Script executed:

# Read ItemTableField.js around lines 75-79
cat -n src/components/mui/FormItemTable/components/ItemTableField.js | sed -n '70,85p'

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 598


🏁 Script executed:

# Read the entire mui-formik-select-v2.js file
wc -l src/components/mui/formik-inputs/mui-formik-select-v2.js

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 143


🏁 Script executed:

# Check MUI version in package.json
grep -A 2 "@mui/material" package.json | head -10

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 300


🏁 Script executed:

# Read the full mui-formik-select-v2.js file
cat -n src/components/mui/formik-inputs/mui-formik-select-v2.js

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 2129


🏁 Script executed:

# Search for other occurrences of shrink in dropdown/select related files
rg -i "shrink" src/components/mui/formik-inputs/ -A 2 -B 2

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 4092


🏁 Script executed:

# Search for displayEmpty usage
rg "displayEmpty" src/components/mui/

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 696


Add shrink prop to InputLabel in MuiFormikSelectV2 to prevent label/placeholder overlap.

The component uses displayEmpty (line 25 of mui-formik-select-v2.js) but the InputLabel lacks the shrink prop, which can cause the floating label to overlap the empty placeholder. Other dropdown components in this codebase (mui-formik-select.js, mui-formik-dropdown-radio.js, mui-formik-dropdown-checkbox.js) already use shrink, and MUI v6 documentation explicitly requires this to prevent overlap when displayEmpty is set.

Fix in src/components/mui/formik-inputs/mui-formik-select-v2.js
-      {label && <InputLabel id={`${name}-label`}>{label}</InputLabel>}
+      {label && <InputLabel shrink id={`${name}-label`}>{label}</InputLabel>}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/FormItemTable/components/ItemTableField.js` around lines
75 - 79, The InputLabel in the MuiFormikSelectV2 component is missing the shrink
prop which causes the floating label to overlap when displayEmpty is used; open
the MuiFormikSelectV2 implementation (symbol: MuiFormikSelectV2) and add shrink
to the label handling — either set InputLabelProps={{ shrink: true }} on the
underlying MUI Select/SelectField or pass shrink directly to the InputLabel
element (symbol: InputLabel) so that displayEmpty remains enabled but the label
is forced to shrink; update any props forwarding (e.g., InputLabelProps) so
callers like ItemTableField using <MuiFormikSelectV2 ... /> inherit this
behavior.

);
case "Text":
return <MuiFormikTextField {...commonProps} fullWidth size="small" />;
Expand Down
9 changes: 8 additions & 1 deletion src/components/mui/FormItemTable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,10 @@ const FormItemTable = ({
{formatRate(row.rates.onsite)}
</TableCell>
{extraColumns.map((exc) => (
<TableCell key={`datacell-${row.form_item_id}-${exc.type_id}`}>
<TableCell
key={`datacell-${row.form_item_id}-${exc.type_id}`}
sx={{ minWidth: 200 }}
>
<ItemTableField
field={exc}
rowId={row.form_item_id}
Expand Down Expand Up @@ -300,3 +303,7 @@ const FormItemTable = ({
};

export default FormItemTable;
export { getCurrentApplicableRate, isItemAvailable } from "./helpers";
export { default as GlobalQuantityField } from "./components/GlobalQuantityField";
export { default as ItemTableField } from "./components/ItemTableField";
export { default as UnderlyingAlertNote } from "./components/UnderlyingAlertNote";
9 changes: 6 additions & 3 deletions src/components/mui/ItemSettingsModal/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@
import React from "react";
import PropTypes from "prop-types";
import T from "i18n-react/dist/i18n-react";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Dialog from "@mui/material/Dialog";
import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogTitle from "@mui/material/DialogTitle";
import { Divider, IconButton, Typography } from "@mui/material";
import Divider from "@mui/material/Divider";
import IconButton from "@mui/material/IconButton";
import Typography from "@mui/material/Typography";
import CloseIcon from "@mui/icons-material/Close";
import ItemTableField from "../FormItemTable/components/ItemTableField";

Expand Down Expand Up @@ -63,14 +66,14 @@ const ItemSettingsModal = ({ item, timeZone, open, onClose }) => {
}}
/>
{itemFields.map((exc) => (
<React.Fragment key={`item-field-${exc.type_id}`}>
<Box key={`item-field-${exc.type_id}`} sx={{ mb: 2 }}>
<ItemTableField
field={exc}
rowId={item.form_item_id}
timeZone={timeZone}
label={exc.name}
/>
</React.Fragment>
</Box>
))}
</DialogContent>
<DialogActions>
Expand Down
3 changes: 2 additions & 1 deletion src/components/mui/formik-inputs/mui-formik-datepicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ const MuiFormikDatepicker = ({
error: meta.touched && Boolean(meta.error),
helperText: meta.touched && meta.error,
fullWidth: true,
disabled
disabled,
size: "small"
},
day: {
sx: {
Expand Down
13 changes: 11 additions & 2 deletions src/components/mui/formik-inputs/mui-formik-dropdown-checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@ import {
Checkbox,
Divider,
FormControl,
InputLabel,
ListItemText,
MenuItem,
Select
} from "@mui/material";
import { useField } from "formik";
import T from "i18n-react/dist/i18n-react";

const MuiFormikDropdownCheckbox = ({ name, options, ...rest }) => {
const MuiFormikDropdownCheckbox = ({ name, label, placeholder, options, ...rest }) => {
const [field, meta, helpers] = useField(name);
const finalPlaceholder = placeholder || T.translate("general.select_an_option");
const allSelected = options.every(({ value }) =>
field.value?.includes(value)
);
Expand All @@ -46,9 +48,16 @@ const MuiFormikDropdownCheckbox = ({ name, options, ...rest }) => {

return (
<FormControl fullWidth error={meta.touched && Boolean(meta.error)}>
{label && (
<InputLabel shrink id={`${name}-label`}>
{label}
</InputLabel>
)}
<Select
variant="outlined"
name={name}
label={label}
labelId={`${name}-label`}
multiple
value={field.value || []}
onChange={handleChange}
Expand All @@ -58,7 +67,7 @@ const MuiFormikDropdownCheckbox = ({ name, options, ...rest }) => {
{...rest}
renderValue={(selected) => {
if (!selected?.length) {
return rest.placeholder || "";
return <em>{finalPlaceholder}</em>;
}
if (allSelected) {
return T.translate("general.all");
Expand Down
10 changes: 9 additions & 1 deletion src/components/mui/formik-inputs/mui-formik-dropdown-radio.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import React from "react";
import {
FormControl,
InputLabel,
ListItemText,
MenuItem,
Radio,
Expand All @@ -22,7 +23,7 @@ import {
import { useField } from "formik";
import T from "i18n-react/dist/i18n-react";

const MuiFormikDropdownRadio = ({ name, options, placeholder, ...rest }) => {
const MuiFormikDropdownRadio = ({ name, label, options, placeholder, ...rest }) => {
const finalPlaceholder =
placeholder || T.translate("general.select_an_option");
const [field, meta, helpers] = useField(name);
Expand All @@ -33,9 +34,16 @@ const MuiFormikDropdownRadio = ({ name, options, placeholder, ...rest }) => {

return (
<FormControl fullWidth error={meta.touched && Boolean(meta.error)}>
{label && (
<InputLabel shrink id={`${name}-label`}>
{label}
</InputLabel>
)}
<Select
variant="outlined"
name={name}
label={label}
labelId={`${name}-label`}
value={field.value || ""}
onChange={handleChange}
displayEmpty
Expand Down
58 changes: 58 additions & 0 deletions src/components/mui/formik-inputs/mui-formik-select-v2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from "react";
import PropTypes from "prop-types";
import T from "i18n-react/dist/i18n-react";
import {
Select,
FormHelperText,
FormControl,
MenuItem,
InputLabel
} from "@mui/material";
import { useField } from "formik";

const MuiFormikSelectV2 = ({ name, label, placeholder, options, ...rest }) => {
const [field, meta] = useField(name);
const finalPlaceholder =
placeholder || T.translate("general.select_an_option");

return (
<FormControl fullWidth error={meta.touched && Boolean(meta.error)}>
{label && <InputLabel id={`${name}-label`}>{label}</InputLabel>}
<Select
name={name}
label={label}
labelId={`${name}-label`}
displayEmpty
// eslint-disable-next-line react/jsx-props-no-spreading
{...field}
// eslint-disable-next-line react/jsx-props-no-spreading
{...rest}
renderValue={(selected) => {
if (selected == null || selected === "") {
return <em>{finalPlaceholder}</em>;
}
const selectedOption = options.find(
({ value }) => value === selected
);
return selectedOption ? selectedOption.label : "";
}}
>
{options.map((op) => (
<MenuItem key={`selectop-${op.value}`} value={op.value}>
{op.label}
</MenuItem>
))}
</Select>
{meta.touched && meta.error && (
<FormHelperText>{meta.error}</FormHelperText>
)}
</FormControl>
);
};

MuiFormikSelectV2.propTypes = {
name: PropTypes.string.isRequired,
options: PropTypes.array.isRequired
};

export default MuiFormikSelectV2;
2 changes: 2 additions & 0 deletions src/components/mui/formik-inputs/mui-formik-timepicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { useField } from "formik";

const MuiFormikTimepicker = ({
name,
label,
minTime,
maxTime,
timeZone,
Expand All @@ -41,6 +42,7 @@ const MuiFormikTimepicker = ({
slotProps={{
textField: {
name,
label,
error: meta.touched && Boolean(meta.error),
helperText: meta.touched && meta.error,
size: "small",
Expand Down
Loading