diff --git a/.browserslistrc b/.browserslistrc index 2c90ae7e7..cc009b0a2 100644 --- a/.browserslistrc +++ b/.browserslistrc @@ -1,2 +1,4 @@ -> 0.25% -not dead +Chrome >= 117 +Edge >= 121 +Firefox >= 121 +Safari >= 17 diff --git a/package.json b/package.json index 53f73d565..d63901c17 100644 --- a/package.json +++ b/package.json @@ -36,14 +36,19 @@ "@codemirror/lang-html": "^6.4.5", "@codemirror/lang-json": "^6.0.1", "@commitlint/config-conventional": "^19.8.1", + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", "@fontsource/roboto": "^5.1.1", - "@mui/icons-material": "^6.4.3", - "@mui/material": "^6.4.3", - "@mui/x-data-grid": "^7.29.13", - "@mui/x-date-pickers": "^7.26.0", - "@mui/x-tree-view": "^7.26.0", + "@googlemaps/markerclusterer": "^2.6.2", + "@hello-pangea/dnd": "^18.0.1", + "@mui/icons-material": "^9.0.0", + "@mui/material": "^9.0.0", + "@mui/x-data-grid": "^9.0.0", + "@mui/x-date-pickers": "^9.0.0", + "@mui/x-tree-view": "^9.0.0", "@react-pdf/renderer": "^4.4.1", "@sentry/react": "^8.32.0", "@sentry/webpack-plugin": "^2.22.4", @@ -51,10 +56,13 @@ "@stripe/stripe-js": "^8.5.3", "@types/googlemaps": "^3.39.3", "@types/markerclustererplus": "^2.1.29", - "@types/react": "^16.9.32", + "@types/react": "^18.0.0", "@uiw/codemirror-theme-sublime": "^4.21.23", "@uiw/react-codemirror": "^4.21.7", "@uiw/react-color-sketch": "^2.1.0", + "@uppy/aws-s3": "^5.1.0", + "@uppy/core": "^5.2.0", + "@vis.gl/react-google-maps": "^1.10.2", "ably": "^2.30.0", "address-rfc2822": "^2.2.2", "awesome-bootstrap-checkbox": "^1.0.1", @@ -72,7 +80,7 @@ "extend": "^3.0.2", "file-loader": "^6.2.0", "file-saver": "^2.0.2", - "final-form": "^4.20.7", + "final-form": "^5.0.1", "font-awesome": "^4.7.0", "formik": "^2.4.6", "graphql-query-builder": "^1.0.7", @@ -95,33 +103,33 @@ "moment-duration-format": "^2.3.2", "moment-timezone": "^0.5.33", "mui-color-input": "^9.0.0", - "openstack-uicore-foundation": "5.0.73-beta.1", + "openstack-uicore-foundation": "6.0.0", "p-limit": "^6.1.0", "path-browserify": "^1.0.1", + "pdfmake": "^0.3.11", "postcss-loader": "^6.2.1", "process": "^0.11.10", "prop-types": "^15.8.1", "qr-scanner": "^1.4.2", - "react": "^16.13.1", - "react-beautiful-dnd": "^13.1.1", + "react": "^18.0.0", "react-bootstrap": "^0.31.5", "react-breadcrumbs": "^2.1.6", "react-chartjs-2": "^5.2.0", "react-data-export": "^0.5.0", - "react-datetime": "^2.15.0", + "react-datetime": "^3.3.1", "react-device-detect": "^2.2.2", "react-dnd": "^16.0.0", "react-dnd-html5-backend": "^16.0.0", - "react-dom": "^16.13.1", + "react-dom": "^18.0.0", "react-dropzone": "^4.2.13", - "react-final-form": "^6.5.9", + "react-final-form": "^7.0.1", "react-google-maps": "^9.4.5", "react-redux": "^7.1.0", "react-router": "^4.3.1", "react-router-dom": "^4.3.1", "react-rte": "^0.16.3", "react-scroll": "^1.7.10", - "react-select": "^2.1.2", + "react-select": "^5.10.2", "react-star-ratings": "^2.3.0", "react-switch": "^6.0.0", "react-tooltip": "^5.28.0", @@ -150,9 +158,9 @@ "@babel/eslint-parser": "^7.24.7", "@testing-library/dom": "^10.1.0", "@testing-library/jest-dom": "^6.4.2", - "@testing-library/react": "12.1.5", + "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^14.5.2", - "@types/react-dom": "16.9.24", + "@types/react-dom": "^18.0.0", "babel-jest": "^30.3.0", "css-minimizer-webpack-plugin": "^4.2.2", "eslint": "8.2.0", @@ -213,6 +221,7 @@ "console": {} }, "maxWorkers": 4, + "testTimeout": 15000, "testEnvironment": "jsdom", "setupFilesAfterEnv": [ "/testSetupFile.js" diff --git a/src/components/audit-logs/index.js b/src/components/audit-logs/index.js index b72afef3c..c34daa534 100644 --- a/src/components/audit-logs/index.js +++ b/src/components/audit-logs/index.js @@ -1,5 +1,5 @@ import React, { useEffect, useState } from "react"; -import { Grid2 } from "@mui/material"; +import { Grid } from "@mui/material"; import SearchInput from "openstack-uicore-foundation/lib/components/mui/search-input"; import MuiTable from "openstack-uicore-foundation/lib/components/mui/table"; import { @@ -180,12 +180,12 @@ const AuditLogs = ({ return ( <> - - - - + + @@ -205,7 +205,6 @@ const AuditLogs = ({ {logEntries.length === 0 && (
{T.translate("audit_log.no_log_entries")}
)} - {logEntries.length > 0 && ( { test("loads the available media types for the given summit", async () => { render(); - await waitFor(() => expect(getAllMediaUploadTypes).toHaveBeenCalledWith(1)); - expect(screen.getByText("Video")).toBeInTheDocument(); + expect(getAllMediaUploadTypes).toHaveBeenCalledWith(1); + // options render once the request resolves + expect(await screen.findByText("Video")).toBeInTheDocument(); expect(screen.getByText("Slides")).toBeInTheDocument(); }); diff --git a/src/components/filters/select-filter-criteria/index.js b/src/components/filters/select-filter-criteria/index.js index dc451148f..48f622649 100644 --- a/src/components/filters/select-filter-criteria/index.js +++ b/src/components/filters/select-filter-criteria/index.js @@ -15,7 +15,7 @@ import React, { useEffect, useState } from "react"; import PropTypes from "prop-types"; import T from "i18n-react/dist/i18n-react"; import Swal from "sweetalert2"; -import AsyncSelect from "react-select/lib/Async"; +import AsyncSelect from "react-select/async"; import { queryFilterCriterias } from "../../../actions/filter-criteria-actions"; import { HIGH_Z_INDEX } from "../../../utils/constants"; diff --git a/src/components/forms/__tests__/badge-settings-form.test.js b/src/components/forms/__tests__/badge-settings-form.test.js index 0986466e8..3bdcb3dd5 100644 --- a/src/components/forms/__tests__/badge-settings-form.test.js +++ b/src/components/forms/__tests__/badge-settings-form.test.js @@ -103,7 +103,10 @@ it("should show the success message and re-enable Save when onSubmit resolves", }) ) ); - expect( - screen.getByRole("button", { name: "general.save" }) - ).not.toBeDisabled(); + // isSaving resets in .finally, after the success message + await waitFor(() => + expect( + screen.getByRole("button", { name: "general.save" }) + ).not.toBeDisabled() + ); }); diff --git a/src/components/forms/__tests__/company-form.test.js b/src/components/forms/__tests__/company-form.test.js index ed1dcc90d..6488fa793 100644 --- a/src/components/forms/__tests__/company-form.test.js +++ b/src/components/forms/__tests__/company-form.test.js @@ -49,10 +49,17 @@ jest.mock( jest.mock( "openstack-uicore-foundation/lib/components/mui/formik-inputs/select", - () => - function MockSelect({ name, children }) { - return
{children}
; - } + () => { + // MUI v9 MenuItems throw outside a Menu/MenuList + const { MenuList } = jest.requireActual("@mui/material"); + return function MockSelect({ name, children }) { + return ( +
+ {children} +
+ ); + }; + } ); jest.mock( diff --git a/src/components/forms/__tests__/media-upload-form.test.js b/src/components/forms/__tests__/media-upload-form.test.js index 19da49d43..20a554b8a 100644 --- a/src/components/forms/__tests__/media-upload-form.test.js +++ b/src/components/forms/__tests__/media-upload-form.test.js @@ -57,10 +57,17 @@ jest.mock( jest.mock( "openstack-uicore-foundation/lib/components/mui/formik-inputs/select", - () => - function MockSelect({ name, children }) { - return
{children}
; - } + () => { + // MUI v9 MenuItems throw outside a Menu/MenuList + const { MenuList } = jest.requireActual("@mui/material"); + return function MockSelect({ name, children }) { + return ( +
+ {children} +
+ ); + }; + } ); jest.mock( diff --git a/src/components/forms/admin-access-form.js b/src/components/forms/admin-access-form.js index f743b8d12..12fcb10b3 100644 --- a/src/components/forms/admin-access-form.js +++ b/src/components/forms/admin-access-form.js @@ -17,7 +17,7 @@ import * as yup from "yup"; import T from "i18n-react/dist/i18n-react"; import Box from "@mui/material/Box"; import Button from "@mui/material/Button"; -import Grid2 from "@mui/material/Grid2"; +import Grid from "@mui/material/Grid"; import Typography from "@mui/material/Typography"; import MemberInput from "openstack-uicore-foundation/lib/components/inputs/member-input"; import SummitInput from "openstack-uicore-foundation/lib/components/inputs/summit-input"; @@ -72,17 +72,17 @@ const AdminAccessForm = ({ sx={{ width: "100%" }} > - - + + - + - + {T.translate("admin_access.members")} * @@ -110,9 +110,9 @@ const AdminAccessForm = ({ {formik.errors.members} )} - + - + {T.translate("admin_access.summits")} * @@ -133,17 +133,17 @@ const AdminAccessForm = ({ {formik.errors.summits} )} - + - - - + + ); diff --git a/src/components/forms/badge-feature-type-form.js b/src/components/forms/badge-feature-type-form.js index 40aef9d7f..c0c135d26 100644 --- a/src/components/forms/badge-feature-type-form.js +++ b/src/components/forms/badge-feature-type-form.js @@ -15,7 +15,7 @@ import React from "react"; import PropTypes from "prop-types"; import T from "i18n-react/dist/i18n-react"; import { useFormikContext } from "formik"; -import { Box, Grid2, InputLabel } from "@mui/material"; +import { Box, Grid, InputLabel } from "@mui/material"; import MuiFormikTextField from "openstack-uicore-foundation/lib/components/mui/formik-inputs/textfield"; import FormikTextEditor from "openstack-uicore-foundation/lib/components/mui/formik-inputs/texteditor"; import UploadInputV3 from "openstack-uicore-foundation/lib/components/inputs/upload-input-v3"; @@ -60,8 +60,8 @@ const BadgeFeatureTypeForm = ({ entity, onRemoveImage, onUploadingChange }) => { return ( - - + + {T.translate("edit_badge_feature.name")} * @@ -71,11 +71,11 @@ const BadgeFeatureTypeForm = ({ entity, onRemoveImage, onUploadingChange }) => { fullWidth size="small" /> - - + + - - + + {T.translate("edit_badge_feature.description")} * @@ -83,11 +83,11 @@ const BadgeFeatureTypeForm = ({ entity, onRemoveImage, onUploadingChange }) => { name="description" licence={process.env.JODIT_LICENSE_KEY} /> - - + + - - + + {T.translate("edit_badge_feature.template_content")} * @@ -95,11 +95,11 @@ const BadgeFeatureTypeForm = ({ entity, onRemoveImage, onUploadingChange }) => { name="template_content" licence={process.env.JODIT_LICENSE_KEY} /> - - + + - - + + {T.translate("edit_badge_feature.image")} { } }} /> - - + + ); }; diff --git a/src/components/forms/badge-form.js b/src/components/forms/badge-form.js index 6b20cb0d5..45b632f6c 100644 --- a/src/components/forms/badge-form.js +++ b/src/components/forms/badge-form.js @@ -399,11 +399,6 @@ class BadgeForm extends React.Component { this.handleChangePrintDate(ev, false) @@ -414,15 +409,15 @@ class BadgeForm extends React.Component { )} className="badge-print-date-picker" renderInput={renderInput} - /> - + this.handleChangePrintDate(ev, true) @@ -433,6 +428,11 @@ class BadgeForm extends React.Component { )} className="badge-print-date-picker" renderInput={renderInput} + inputProps={{ + placeholder: T.translate( + "edit_ticket.placeholders.print_date_to" + ) + }} /> - - + + )} {initialEntity?.project_sponsorships?.length > 0 && window.APP_CLIENT_NAME === "openstack" && ( - + ({ ...sp, @@ -364,11 +364,11 @@ const CompanyForm = ({ columns={sponsored_project_columns} onDelete={handleDeleteSponsorship} /> - + )} - - + + {T.translate("edit_company.logo")} - + + {T.translate("edit_company.big_logo")} - - + + + ); }; diff --git a/src/components/forms/email-flow-event-form/index.js b/src/components/forms/email-flow-event-form/index.js index 76d5d22ee..35905c3ac 100644 --- a/src/components/forms/email-flow-event-form/index.js +++ b/src/components/forms/email-flow-event-form/index.js @@ -16,7 +16,7 @@ import { useFormikContext } from "formik"; import Box from "@mui/material/Box"; import FormLabel from "@mui/material/FormLabel"; import Typography from "@mui/material/Typography"; -import { Grid2 } from "@mui/material"; +import { Grid } from "@mui/material"; import MuiFormikTextField from "openstack-uicore-foundation/lib/components/mui/formik-inputs/textfield"; import useScrollToError from "../../../hooks/useScrollToError"; import EmailTemplateInput from "../../inputs/email-template-input"; @@ -35,25 +35,25 @@ const EmailFlowEventForm = ({ entity }) => { return ( - - + + {T.translate("edit_email_flow_event.flow_name")} {entity.flow_name} - - + + {T.translate("edit_email_flow_event.event_type")} {entity.event_type_name} - - + + - - + + {T.translate("edit_email_flow_event.email_template_identifier")} * {values.email_template_identifier && ( @@ -83,8 +83,8 @@ const EmailFlowEventForm = ({ entity }) => { onChange={handleTemplateChange} plainValue /> - - + + {T.translate("edit_email_flow_event.recipient")} @@ -94,14 +94,14 @@ const EmailFlowEventForm = ({ entity }) => { fullWidth size="small" /> - - + + {T.translate("edit_email_flow_event.variables")} - - + + ); }; diff --git a/src/components/forms/email-flow-event-form/template-schema-tree.js b/src/components/forms/email-flow-event-form/template-schema-tree.js index b10e11384..c423afdbf 100644 --- a/src/components/forms/email-flow-event-form/template-schema-tree.js +++ b/src/components/forms/email-flow-event-form/template-schema-tree.js @@ -1,5 +1,5 @@ import React, { useEffect, useState } from "react"; -import { Grid2 } from "@mui/material"; +import { Grid } from "@mui/material"; import { SimpleTreeView } from "@mui/x-tree-view/SimpleTreeView"; import { TreeItem } from "@mui/x-tree-view/TreeItem"; @@ -84,21 +84,21 @@ const TemplateSchemaTree = ({ templateSchema }) => { const columns = [treeData.slice(0, midpoint), treeData.slice(midpoint)]; return ( - + {columns.map( (columnNodes, columnIndex) => columnNodes.length > 0 && ( // eslint-disable-next-line react/no-array-index-key - + {toTreeItems(columnNodes, `col${columnIndex}`)} - + ) )} - + ); }; diff --git a/src/components/forms/event-category-form.js b/src/components/forms/event-category-form.js index 1b473df0a..3d8b28dd6 100644 --- a/src/components/forms/event-category-form.js +++ b/src/components/forms/event-category-form.js @@ -22,7 +22,7 @@ import { Autocomplete, Box, Button, - Grid2, + Grid, InputLabel, TextField, Tooltip, @@ -201,44 +201,44 @@ const EventCategoryForm = ({ return ( - - + + {T.translate("edit_event_category.name")} * - - + + {T.translate("edit_event_category.code")} * - - + + {T.translate("edit_event_category.color")} * - - + + {T.translate("edit_event_category.text_color")} * - - + + - - + + {T.translate("edit_event_category.description")} * - - + + - - + + {T.translate("edit_event_category.number_sessions")} @@ -248,8 +248,8 @@ const EventCategoryForm = ({ margin="none" fullWidth /> - - + + {T.translate("edit_event_category.number_alternates")} @@ -259,8 +259,8 @@ const EventCategoryForm = ({ margin="none" fullWidth /> - - + + {T.translate("edit_event_category.number_lightning")} @@ -270,8 +270,8 @@ const EventCategoryForm = ({ margin="none" fullWidth /> - - + + {T.translate("edit_event_category.number_lightning_alternates")} @@ -281,26 +281,26 @@ const EventCategoryForm = ({ margin="none" fullWidth /> - - + + - - + + - - + + - - + + - - + + {T.translate("edit_event_category.tags")} @@ -320,11 +320,11 @@ const EventCategoryForm = ({ })} formatSelectedValue={(s) => ({ value: s.value, label: s.label })} /> - - + + - - + + ({ value: s.value, label: s.label })} /> - - + + {entity.id !== 0 && ( - - + + {T.translate("edit_event_category.pic")} @@ -381,8 +381,8 @@ const EventCategoryForm = ({ } }} /> - - + + )} - - + + {T.translate( "edit_event_category.proposed_schedule_settings.transition_time" @@ -415,23 +415,23 @@ const EventCategoryForm = ({ )} slotProps={{ htmlInput: { min: 1, max: 240 } }} /> - - + + {!!entity.id && !entity.parent?.id && ( - - + + {T.translate("edit_event_category.subtracks")}  (Nested tracks on schedule filter widget) - - - - + + + + t.name} @@ -447,8 +447,8 @@ const EventCategoryForm = ({ /> )} /> - - + + - - + +
@@ -1626,15 +1626,15 @@ class EventForm extends React.Component { entity.end_date, currentSummit.time_zone_id )} - inputProps={{ - placeholder: T.translate("edit_event.placeholders.end_date") - }} timezone={currentSummit.time_zone_id} error={hasErrors("end_date", errors)} viewDate={epochToMomentTimeZone( currentSummit.start_date, currentSummit.time_zone_id )} + inputProps={{ + placeholder: T.translate("edit_event.placeholders.end_date") + }} />
@@ -1988,7 +1988,6 @@ class EventForm extends React.Component { />
)} - {this.shouldShowField("allows_attachment") && (
@@ -2313,7 +2312,6 @@ class EventForm extends React.Component { )} )} - {entity.id !== 0 && entity.selection_plan?.extra_questions?.length > 0 && ( )} - {entity.id !== 0 && entity.allow_feedback && ( )} - )} -
-
{!entity.is_published && ( diff --git a/src/components/forms/marketing-setting-form.js b/src/components/forms/marketing-setting-form.js index dd4c54f49..8a59078eb 100644 --- a/src/components/forms/marketing-setting-form.js +++ b/src/components/forms/marketing-setting-form.js @@ -16,7 +16,7 @@ import PropTypes from "prop-types"; import T from "i18n-react/dist/i18n-react"; import { useFormikContext } from "formik"; import Box from "@mui/material/Box"; -import { Grid2 } from "@mui/material"; +import { Grid } from "@mui/material"; import MenuItem from "@mui/material/MenuItem"; import FormHelperText from "@mui/material/FormHelperText"; import MuiFormikTextField from "openstack-uicore-foundation/lib/components/mui/formik-inputs/textfield"; @@ -78,8 +78,8 @@ const MarketingSettingForm = ({ onDeleteImage }) => { return ( - - + + { ))} - - + + - - + + @@ -114,12 +114,12 @@ const MarketingSettingForm = ({ onDeleteImage }) => { fullWidth size="small" /> - - + + - + {values.type === MARKETING_SETTING_TYPE_TEXT && ( - + @@ -129,10 +129,10 @@ const MarketingSettingForm = ({ onDeleteImage }) => { fullWidth size="small" /> - + )} {values.type === MARKETING_SETTING_TYPE_TEXTAREA && ( - + { error={valueError} license={process.env.JODIT_LICENSE_KEY} /> - + )} {values.type === MARKETING_SETTING_TYPE_FILE && ( - + {/* need this styles to adapt bootstrap to MUI */} { /> {fileError && {fileError}} - + )} {values.type === MARKETING_SETTING_TYPE_HEX_COLOR && ( - + - + )} - + ); }; diff --git a/src/components/forms/media-upload-form.js b/src/components/forms/media-upload-form.js index 391e2fb94..8417387c1 100644 --- a/src/components/forms/media-upload-form.js +++ b/src/components/forms/media-upload-form.js @@ -20,7 +20,7 @@ import Autocomplete from "@mui/material/Autocomplete"; import Box from "@mui/material/Box"; import Button from "@mui/material/Button"; import Divider from "@mui/material/Divider"; -import Grid2 from "@mui/material/Grid2"; +import Grid from "@mui/material/Grid"; import InputAdornment from "@mui/material/InputAdornment"; import InputLabel from "@mui/material/InputLabel"; import MenuItem from "@mui/material/MenuItem"; @@ -136,17 +136,17 @@ const MediaUploadForm = ({ component="form" onSubmit={formik.handleSubmit} > - - + + {T.translate("media_upload.name")} * - - + + - - + + {T.translate("media_upload.max_size")} * @@ -157,8 +157,8 @@ const MediaUploadForm = ({ margin="none" fullWidth /> - - + + {T.translate("media_upload.min_qty")} @@ -168,8 +168,8 @@ const MediaUploadForm = ({ margin="none" fullWidth /> - - + + - - + + - - + + {T.translate("media_upload.description")} - - + + - - + + {T.translate("media_upload.type")} @@ -211,19 +211,19 @@ const MediaUploadForm = ({ ))} - - + + - - + + - - + + {T.translate("media_upload.private_storage_type")} @@ -239,8 +239,8 @@ const MediaUploadForm = ({ ))} - - + + {T.translate("media_upload.public_storage_type")} @@ -256,20 +256,20 @@ const MediaUploadForm = ({ ))} - - + + - - + + {values.use_temporary_links_on_public_storage && ( - - + + {T.translate( "media_upload.temporary_links_public_storage_ttl_info" @@ -290,14 +290,14 @@ const MediaUploadForm = ({ } }} /> - - + + )} - - + + )} /> - - + + diff --git a/src/components/forms/schedule-settings-form/__tests__/schedule-settings-form.test.js b/src/components/forms/schedule-settings-form/__tests__/schedule-settings-form.test.js index 7ee306ede..0acb805df 100644 --- a/src/components/forms/schedule-settings-form/__tests__/schedule-settings-form.test.js +++ b/src/components/forms/schedule-settings-form/__tests__/schedule-settings-form.test.js @@ -151,7 +151,7 @@ describe("ScheduleSettingsForm", () => { await userEvent.click( screen.getByRole("button", { name: "reverse-filters" }) ); - await userEvent.click(screen.getByRole("checkbox", { name: "Category" })); + await userEvent.click(screen.getByRole("switch", { name: "Category" })); await clickSave(); const { filters } = onSubmit.mock.calls[0][0]; @@ -166,17 +166,17 @@ describe("ScheduleSettingsForm", () => { test("turning off Enabled disables the rest of the form", async () => { await renderForm(); - const myScheduleSwitch = screen.getByRole("checkbox", { + const myScheduleSwitch = screen.getByRole("switch", { name: "edit_schedule_settings.is_my_schedule" }); expect(myScheduleSwitch).toBeEnabled(); await userEvent.click( - screen.getByRole("checkbox", { name: "edit_schedule_settings.enabled" }) + screen.getByRole("switch", { name: "edit_schedule_settings.enabled" }) ); expect(myScheduleSwitch).toBeDisabled(); - expect(screen.getByRole("checkbox", { name: "Category" })).toBeDisabled(); + expect(screen.getByRole("switch", { name: "Category" })).toBeDisabled(); }); test("hides pre-filter types without an input", async () => { diff --git a/src/components/forms/schedule-settings-form/index.js b/src/components/forms/schedule-settings-form/index.js index 9da62e18b..b4c038b86 100644 --- a/src/components/forms/schedule-settings-form/index.js +++ b/src/components/forms/schedule-settings-form/index.js @@ -18,7 +18,7 @@ import T from "i18n-react/dist/i18n-react"; import { Box, Button, - Grid2, + Grid, InputLabel, MenuItem, Typography @@ -152,23 +152,23 @@ const ScheduleSettingsForm = ({ entity, summit, errors, onSubmit }) => { return ( - - + + {T.translate("edit_schedule_settings.key")} - - + + - - + + - - + + {T.translate("edit_schedule_settings.color_source")} * @@ -186,8 +186,8 @@ const ScheduleSettingsForm = ({ entity, summit, errors, onSubmit }) => { ))} - - + + {T.translate("edit_schedule_settings.time_format")} * @@ -198,32 +198,32 @@ const ScheduleSettingsForm = ({ entity, summit, errors, onSubmit }) => { ))} - - + + - - + + - - + + - - + + - - + + {T.translate("edit_schedule_settings.filters")} @@ -239,21 +239,21 @@ const ScheduleSettingsForm = ({ entity, summit, errors, onSubmit }) => { {T.translate("edit_schedule_settings.pre_filters")} - + {values.pre_filters.map( (pf, idx) => !HIDDEN_PRE_FILTERS.includes(pf.type) && ( - + - + ) )} - + - - + + {values.extra_questions.length === 0 && (
{T.translate("edit_selection_plan.no_extra_questions")}
)} diff --git a/src/components/forms/selection-plan-form/main-tab.js b/src/components/forms/selection-plan-form/main-tab.js index 5aecf6093..9b5aed9dc 100644 --- a/src/components/forms/selection-plan-form/main-tab.js +++ b/src/components/forms/selection-plan-form/main-tab.js @@ -18,7 +18,7 @@ import { useFormikContext } from "formik"; import TextEditorV3 from "openstack-uicore-foundation/lib/components/inputs/editor-input-v3"; import Checkbox from "@mui/material/Checkbox"; import FormControlLabel from "@mui/material/FormControlLabel"; -import Grid2 from "@mui/material/Grid2"; +import Grid from "@mui/material/Grid"; import TextField from "@mui/material/TextField"; import MuiFormikDatetimepicker from "../../mui/formik-inputs/mui-formik-datetimepicker"; @@ -35,8 +35,8 @@ const MainTab = ({ hidden, currentSummit }) => { return ( ); }; diff --git a/src/components/forms/selection-plan-form/presentation-action-types-tab.js b/src/components/forms/selection-plan-form/presentation-action-types-tab.js index 9358ee35e..82e2bdb74 100644 --- a/src/components/forms/selection-plan-form/presentation-action-types-tab.js +++ b/src/components/forms/selection-plan-form/presentation-action-types-tab.js @@ -17,7 +17,7 @@ import T from "i18n-react/dist/i18n-react"; import { useFormikContext } from "formik"; import SortableTable from "openstack-uicore-foundation/lib/components/mui/sortable-table"; import Box from "@mui/material/Box"; -import Grid2 from "@mui/material/Grid2"; +import Grid from "@mui/material/Grid"; import Many2ManyDropDown from "../../inputs/many-2-many-dropdown"; import { querySummitProgressFlags } from "../../../actions/track-chair-actions"; @@ -56,8 +56,8 @@ const PresentationActionTypesTab = ({ hidden={hidden} > - - + + - - + + {values.allowed_presentation_action_types.length === 0 && (
{T.translate("edit_selection_plan.no_presentation_action_types")} diff --git a/src/components/forms/sponsor-settings-form/index.js b/src/components/forms/sponsor-settings-form/index.js index 8634406ae..dc886399d 100644 --- a/src/components/forms/sponsor-settings-form/index.js +++ b/src/components/forms/sponsor-settings-form/index.js @@ -15,7 +15,7 @@ import React from "react"; import T from "i18n-react/dist/i18n-react"; import { useFormik, FormikProvider } from "formik"; import * as yup from "yup"; -import { Box, Button, Grid2 } from "@mui/material"; +import { Box, Button, Grid } from "@mui/material"; import { epochToMomentTimeZone } from "openstack-uicore-foundation/lib/utils/methods"; import MuiFormikDatepicker from "openstack-uicore-foundation/lib/components/mui/formik-inputs/datepicker"; import MuiFormikTextField from "openstack-uicore-foundation/lib/components/mui/formik-inputs/textfield"; @@ -121,32 +121,32 @@ const SponsorSettingsForm = ({ settings, onSubmit, summitTZ }) => { className={styles.formWrapper} autoComplete="off" > - - + + - - + + - - + + - - + + - - + + { fullWidth margin="none" /> - - + + { )} fullWidth /> - - + + { rows={4} type="text" /> - - + + { rows={4} type="text" /> - - + + - - + + - - + + diff --git a/src/components/inputs/__tests__/edit-label-slider.test.js b/src/components/inputs/__tests__/edit-label-slider.test.js index cb7133060..43ac68dec 100644 --- a/src/components/inputs/__tests__/edit-label-slider.test.js +++ b/src/components/inputs/__tests__/edit-label-slider.test.js @@ -39,7 +39,7 @@ describe("EditLabelSlider", () => { test("toggling the switch updates is_enabled", async () => { renderWithFormik(); - await userEvent.click(screen.getByRole("checkbox", { name: "Category" })); + await userEvent.click(screen.getByRole("switch", { name: "Category" })); expect(fieldValue().is_enabled).toBe(true); }); @@ -120,6 +120,6 @@ describe("EditLabelSlider", () => { expect( screen.queryByRole("button", { name: "edit_schedule_settings.edit_name" }) ).not.toBeInTheDocument(); - expect(screen.getByRole("checkbox", { name: "Category" })).toBeDisabled(); + expect(screen.getByRole("switch", { name: "Category" })).toBeDisabled(); }); }); diff --git a/src/components/inputs/badge-feature-input.js b/src/components/inputs/badge-feature-input.js index d1abce500..e9ae06f12 100644 --- a/src/components/inputs/badge-feature-input.js +++ b/src/components/inputs/badge-feature-input.js @@ -9,12 +9,11 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - **/ + * */ import React from "react"; -import AsyncSelect from "react-select/lib/Async"; +import AsyncSelect from "react-select/async"; import { queryBadgeFeatures } from "../../actions/badge-actions"; -import { shallowEqual } from "../../utils/methods"; export default class BadgeFeatureInput extends React.Component { constructor(props) { @@ -30,7 +29,7 @@ export default class BadgeFeatureInput extends React.Component { if (this.props.hasOwnProperty("getOptionValue")) { return this.props.getOptionValue(badgeFeature); } - //default + // default return badgeFeature.id; } @@ -38,7 +37,7 @@ export default class BadgeFeatureInput extends React.Component { if (this.props.hasOwnProperty("getOptionLabel")) { return this.props.getOptionLabel(badgeFeature); } - //default + // default return `${badgeFeature.name}`; } @@ -46,7 +45,7 @@ export default class BadgeFeatureInput extends React.Component { const ev = { target: { id: this.props.id, - value: value, + value, type: "badgefeatureinput" } }; diff --git a/src/components/inputs/edit-label-slider.js b/src/components/inputs/edit-label-slider.js index 915d3675e..80035d5f6 100644 --- a/src/components/inputs/edit-label-slider.js +++ b/src/components/inputs/edit-label-slider.js @@ -41,7 +41,7 @@ const EditLabelSlider = ({ name, disabled = false }) => { checked={!!enabledField.value} onChange={enabledField.onChange} disabled={disabled} - inputProps={{ "aria-label": labelField.value }} + slotProps={{ input: { "aria-label": labelField.value } }} /> {labelField.value} {!editing && !disabled && ( @@ -62,8 +62,10 @@ const EditLabelSlider = ({ name, disabled = false }) => { handleSave(); } }} - inputProps={{ - "aria-label": T.translate("edit_schedule_settings.edit_name") + slotProps={{ + htmlInput: { + "aria-label": T.translate("edit_schedule_settings.edit_name") + } }} /> - - + + {disabled ? ( diff --git a/src/components/mui/__tests__/bulk-edit-data-grid.test.js b/src/components/mui/__tests__/bulk-edit-data-grid.test.js index c89aa0625..39d54b855 100644 --- a/src/components/mui/__tests__/bulk-edit-data-grid.test.js +++ b/src/components/mui/__tests__/bulk-edit-data-grid.test.js @@ -60,7 +60,8 @@ describe("BulkEditDataGrid", () => { const titleInput = screen.getByDisplayValue("Second"); await userEvent.clear(titleInput); - await userEvent.type(titleInput, "Renamed"); + // pasted: typing it key by key re-renders the auto-height grid per key and is slow + await userEvent.paste("Renamed"); await userEvent.click( screen.getByRole("button", { name: "bulk_edit_table.apply_changes" }) ); @@ -294,7 +295,7 @@ describe("BulkEditDataGrid", () => { const clickDelete = (rowName) => userEvent.click( within(screen.getByRole("row", { name: new RegExp(rowName) })).getByRole( - "menuitem", + "button", { name: "general.delete" } ) ); diff --git a/src/components/mui/bulk-edit-data-grid/index.js b/src/components/mui/bulk-edit-data-grid/index.js index 50e085ccc..50733cde2 100644 --- a/src/components/mui/bulk-edit-data-grid/index.js +++ b/src/components/mui/bulk-edit-data-grid/index.js @@ -143,6 +143,16 @@ const BulkEditDataGrid = ({ reset(); }, [dataIds]); + // MUI X v8+ selection is { type, ids }; "exclude" (select all) means every row but ids + const handleSelectionChange = ({ type, ids }) => { + const rowIds = data.map((row) => row[idKey]); + setSelectedIds( + type === "exclude" + ? rowIds.filter((id) => !ids.has(id)) + : rowIds.filter((id) => ids.has(id)) + ); + }; + const enterEditMode = () => { setEditRows( Object.fromEntries( @@ -309,8 +319,8 @@ const BulkEditDataGrid = ({ getRowHeight={({ id }) => (editRows[id] ? "auto" : null)} checkboxSelection disableRowSelectionOnClick - rowSelectionModel={selectedIds} - onRowSelectionModelChange={setSelectedIds} + rowSelectionModel={{ type: "include", ids: new Set(selectedIds) }} + onRowSelectionModelChange={handleSelectionChange} isRowSelectable={() => !editEnabled} columnVisibilityModel={columnVisibilityModel} onColumnVisibilityModelChange={onColumnVisibilityModelChange} @@ -330,6 +340,7 @@ const BulkEditDataGrid = ({ ...(noRowsLabel && { noRowsLabel }) }} hideFooter + showToolbar slots={{ toolbar: Toolbar, columnMenu: ColumnMenu }} slotProps={{ panel: { anchorEl: columnsButtonEl, placement: "bottom-end" }, diff --git a/src/components/mui/dnd-list.js b/src/components/mui/dnd-list.js index 78501ab92..95d11a351 100644 --- a/src/components/mui/dnd-list.js +++ b/src/components/mui/dnd-list.js @@ -1,6 +1,6 @@ import React from "react"; import PropTypes from "prop-types"; -import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"; +import { DragDropContext, Droppable, Draggable } from "@hello-pangea/dnd"; import { Box } from "@mui/material"; const reorder = (list, startIndex, endIndex, updateOrderKey) => { diff --git a/src/components/mui/formik-inputs/item-price-tiers.js b/src/components/mui/formik-inputs/item-price-tiers.js index 2a98aec16..a7353a324 100644 --- a/src/components/mui/formik-inputs/item-price-tiers.js +++ b/src/components/mui/formik-inputs/item-price-tiers.js @@ -5,7 +5,7 @@ import { Box, Checkbox, FormControlLabel, - Grid2, + Grid, InputLabel, TextField } from "@mui/material"; @@ -32,11 +32,11 @@ const ItemPriceTiers = ({ readOnly = false }) => { }; return ( - + {TIERS.map(({ field, label }) => { const isEnabled = enabled[field]; return ( - + { onChange={(ev) => handleToggle(field, ev.target.checked)} size="small" disabled={readOnly} - inputProps={{ - "aria-label": `${T.translate(label)} ${T.translate( - "price_tiers.not_available" - )}` + slotProps={{ + input: { + "aria-label": `${T.translate(label)} ${T.translate( + "price_tiers.not_available" + )}` + } }} /> } @@ -80,10 +82,10 @@ const ItemPriceTiers = ({ readOnly = false }) => { /> )} - + ); })} - + ); }; diff --git a/src/components/mui/formik-inputs/mui-formik-async-select.js b/src/components/mui/formik-inputs/mui-formik-async-select.js index 54474c7c5..dbd90dd6e 100644 --- a/src/components/mui/formik-inputs/mui-formik-async-select.js +++ b/src/components/mui/formik-inputs/mui-formik-async-select.js @@ -126,15 +126,18 @@ const MuiFormikAsyncAutocomplete = ({ error={Boolean(error)} helperText={error || ""} slotProps={{ + ...params.slotProps, + input: { - ...params.InputProps, + ...params.slotProps.input, endAdornment: ( <> {loading && } - {params.InputProps?.endAdornment} + {params.slotProps.input?.endAdornment} ) }, + inputLabel: { shrink: false } }} sx={{ diff --git a/src/components/mui/menu-button.js b/src/components/mui/menu-button.js index 2ab8c01bd..e55ea8be2 100644 --- a/src/components/mui/menu-button.js +++ b/src/components/mui/menu-button.js @@ -68,10 +68,8 @@ const MenuButton = ({ anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleClose} - MenuListProps={{ - "aria-labelledby": buttonId - }} slotProps={{ + list: { "aria-labelledby": buttonId }, paper: { sx: { minWidth: 220 } } diff --git a/src/components/mui/showConfirmDialog.js b/src/components/mui/showConfirmDialog.js index ee3a368fd..effb06c0a 100644 --- a/src/components/mui/showConfirmDialog.js +++ b/src/components/mui/showConfirmDialog.js @@ -1,4 +1,4 @@ -import ReactDOM from "react-dom"; +import { createRoot } from "react-dom/client"; import React from "react"; import ConfirmDialog from "./confirm-dialog"; @@ -14,9 +14,10 @@ const showConfirmDialog = ({ new Promise((resolve) => { const container = document.createElement("div"); document.body.appendChild(container); + const root = createRoot(container); const close = (answer) => { - ReactDOM.unmountComponentAtNode(container); + root.unmount(); container.remove(); resolve(answer); }; @@ -24,7 +25,7 @@ const showConfirmDialog = ({ const handleConfirm = () => close(true); const handleCancel = () => close(false); - ReactDOM.render( + root.render( , - container + /> ); }); diff --git a/src/components/schedule-builder/schedule-admin-empty-spots-modal.js b/src/components/schedule-builder/schedule-admin-empty-spots-modal.js index c167182d2..c1fdcb1ee 100644 --- a/src/components/schedule-builder/schedule-admin-empty-spots-modal.js +++ b/src/components/schedule-builder/schedule-admin-empty-spots-modal.js @@ -9,27 +9,40 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - **/ -import { Modal, Button, FormGroup, FormControl } from "react-bootstrap"; + */ import React from "react"; -import DateTimePicker from "openstack-uicore-foundation/lib/components/inputs/datetimepicker" -import SummitVenuesSelect from "openstack-uicore-foundation/lib/components/inputs/summit-venues-select"; -import moment from "moment-timezone"; +import { Modal, Button, FormGroup, FormControl } from "react-bootstrap"; import T from "i18n-react/dist/i18n-react"; +import moment from "moment-timezone"; +import DateTimePicker from "openstack-uicore-foundation/lib/components/inputs/datetimepicker"; +import SummitVenuesSelect from "openstack-uicore-foundation/lib/components/inputs/summit-venues-select"; +import { MILLISECONDS_IN_SECOND } from "../../utils/constants"; + +const DEFAULT_START_HOUR = 7; +const DEFAULT_END_HOUR = 19; +const END_OF_DAY_HOUR = 23; +const END_OF_HOUR = 59; +const MIN_GAP_MINUTES = 5; class ScheduleAdminEmptySpotsModal extends React.Component { constructor(props) { super(props); const { currentSummit } = this.props; - let defaultValueStart = moment - .tz(currentSummit.start_date * 1000, currentSummit.time_zone.name) - .hour(7) + const defaultValueStart = moment + .tz( + currentSummit.start_date * MILLISECONDS_IN_SECOND, + currentSummit.time_zone.name + ) + .hour(DEFAULT_START_HOUR) .minute(0) .second(0); - let defaultValueEnd = moment - .tz(currentSummit.start_date * 1000, currentSummit.time_zone.name) - .hour(19) + const defaultValueEnd = moment + .tz( + currentSummit.start_date * MILLISECONDS_IN_SECOND, + currentSummit.time_zone.name + ) + .hour(DEFAULT_END_HOUR) .minute(0) .second(0); @@ -56,7 +69,7 @@ class ScheduleAdminEmptySpotsModal extends React.Component { isValidForm() { let valid = true; - for (var key in this.validationState) { + for (const key in this.validationState) { valid = valid && this.validationState[key]; } return valid; @@ -66,32 +79,32 @@ class ScheduleAdminEmptySpotsModal extends React.Component { if (!this.isValidForm()) return; this.props.onFindEmptySpots({ currentLocation: this.state.currentLocation.value, - dateFrom: this.state.dateFrom.valueOf() / 1000, - dateTo: this.state.dateTo.valueOf() / 1000, + dateFrom: this.state.dateFrom.valueOf() / MILLISECONDS_IN_SECOND, + dateTo: this.state.dateTo.valueOf() / MILLISECONDS_IN_SECOND, gapSize: this.state.gapSize }); } handleChangeDateFrom(ev) { - let { value, id } = ev.target; + const { value } = ev.target; this.setState({ ...this.state, dateFrom: value }); } getValidationDateFrom() { - let { dateFrom } = this.state; - let isValid = dateFrom != null && dateFrom !== ""; + const { dateFrom } = this.state; + const isValid = dateFrom != null && dateFrom !== ""; this.validationState = { ...this.validationState, dateFrom: isValid }; return isValid ? "success" : "warning"; } handleChangeDateTo(ev) { - let { value, id } = ev.target; + const { value } = ev.target; this.setState({ ...this.state, dateTo: value }); } getValidationDateTo() { - let { dateTo, dateFrom } = this.state; - let isValid = + const { dateTo, dateFrom } = this.state; + const isValid = dateTo != null && dateTo !== "" && dateFrom != null && @@ -101,15 +114,15 @@ class ScheduleAdminEmptySpotsModal extends React.Component { } onVenueChanged(location) { - let option = + const option = location != null ? { value: location, label: location.name } : null; this.setState({ ...this.state, currentLocation: option }); } getValidationStateVenue() { - let { currentLocation } = this.state; + const { currentLocation } = this.state; - let isValid = currentLocation != null; + const isValid = currentLocation != null; this.validationState = { ...this.validationState, currentLocation: isValid @@ -124,51 +137,47 @@ class ScheduleAdminEmptySpotsModal extends React.Component { getValidationStateGapSize() { let { gapSize } = this.state; gapSize = parseInt(gapSize); - let isValid = gapSize >= 5; + const isValid = gapSize >= MIN_GAP_MINUTES; this.validationState = { ...this.validationState, gapSize: isValid }; return isValid ? "success" : "warning"; } render() { - let { showModal, onCloseModal, currentSummit } = this.props; - let { currentLocation, dateFrom, dateTo, gapSize } = this.state; + const { showModal, onCloseModal, currentSummit } = this.props; + const { currentLocation, dateFrom, dateTo, gapSize } = this.state; // process venues - let venues = []; + const venues = []; for (let i = 0; i < currentSummit.locations.length; i++) { - let location = currentSummit.locations[i]; + const location = currentSummit.locations[i]; if (location.class_name !== "SummitVenue") continue; - let option = { value: location, label: location.name }; + const option = { value: location, label: location.name }; venues.push(option); if (!location.hasOwnProperty("rooms")) continue; for (let j = 0; j < location.rooms.length; j++) { - let subOption = { + const subOption = { value: location.rooms[j], label: location.rooms[j].name }; venues.push(subOption); } } - let currenSummitStartDate = moment - .tz(currentSummit.start_date * 1000, currentSummit.time_zone.name) + const currenSummitStartDate = moment + .tz( + currentSummit.start_date * MILLISECONDS_IN_SECOND, + currentSummit.time_zone.name + ) .hour(0) .minute(0) .second(0); - let currenSummitEndDate = moment - .tz(currentSummit.end_date * 1000, currentSummit.time_zone.name) - .hour(23) - .minute(59) - .second(59); - let defaultValueStart = moment - .tz(currentSummit.start_date * 1000, currentSummit.time_zone.name) - .hour(7) - .minute(0) - .second(0); - let defaultValueEnd = moment - .tz(currentSummit.start_date * 1000, currentSummit.time_zone.name) - .hour(22) - .minute(0) - .second(0); + const currenSummitEndDate = moment + .tz( + currentSummit.end_date * MILLISECONDS_IN_SECOND, + currentSummit.time_zone.name + ) + .hour(END_OF_DAY_HOUR) + .minute(END_OF_HOUR) + .second(END_OF_HOUR); return ( @@ -201,19 +210,22 @@ class ScheduleAdminEmptySpotsModal extends React.Component { @@ -225,18 +237,21 @@ class ScheduleAdminEmptySpotsModal extends React.Component { id="end_date" format={{ date: "YYYY-MM-DD", time: "HH:mm" }} timeConstraints={{ hours: { min: 7, max: 22 } }} - inputProps={{ - placeholder: T.translate( - "empty_spots_modal.placeholders.end_date" - ) - }} timezone={currentSummit.time_zone.name} validation={{ - after: currenSummitStartDate.valueOf() / 1000, - before: currenSummitEndDate.valueOf() / 1000 + after: + currenSummitStartDate.valueOf() / + MILLISECONDS_IN_SECOND, + before: + currenSummitEndDate.valueOf() / MILLISECONDS_IN_SECOND }} onChange={this.handleChangeDateTo} value={dateTo} + inputProps={{ + placeholder: T.translate( + "empty_spots_modal.placeholders.end_date" + ) + }} /> diff --git a/src/components/select-page-template-dialog/index.js b/src/components/select-page-template-dialog/index.js index dadac1f65..1989c6927 100644 --- a/src/components/select-page-template-dialog/index.js +++ b/src/components/select-page-template-dialog/index.js @@ -11,7 +11,7 @@ import { DialogTitle, Divider, FormControlLabel, - Grid2, + Grid, IconButton, Radio, Typography @@ -153,18 +153,18 @@ const SelectPageTemplateDialog = ({ - - + + {selectedRows.length} items selected - - + + - - + + {pageTemplates.length > 0 && ( diff --git a/src/components/sponsors/reports/ByItemView.js b/src/components/sponsors/reports/ByItemView.js index 81c686e62..340d3d2d1 100644 --- a/src/components/sponsors/reports/ByItemView.js +++ b/src/components/sponsors/reports/ByItemView.js @@ -423,7 +423,10 @@ const ItemTable = ({ colSpan={ITEM_HEADERS.length + 1} sx={{ bgcolor: "grey.50", py: 1.5 }} > - + {T.translate( "sponsor_reports_page.byitem_contributing_orders" )} diff --git a/src/components/sponsors/reports/ContentCell.js b/src/components/sponsors/reports/ContentCell.js index 0849fc89f..c78f0f3a3 100644 --- a/src/components/sponsors/reports/ContentCell.js +++ b/src/components/sponsors/reports/ContentCell.js @@ -68,9 +68,8 @@ const ContentCell = ({ row }) => { } return ( diff --git a/src/components/sponsors/reports/FilterBar.js b/src/components/sponsors/reports/FilterBar.js index 6f6506458..5179418f5 100644 --- a/src/components/sponsors/reports/FilterBar.js +++ b/src/components/sponsors/reports/FilterBar.js @@ -39,7 +39,7 @@ const FilterBar = ({ return ( - + {T.translate("sponsor_reports_page.report_filters")} @@ -48,8 +48,7 @@ const FilterBar = ({ {showSearch && ( diff --git a/src/components/sponsors/reports/LinesManifestView.js b/src/components/sponsors/reports/LinesManifestView.js index 9b955d1f3..0e78ffe1b 100644 --- a/src/components/sponsors/reports/LinesManifestView.js +++ b/src/components/sponsors/reports/LinesManifestView.js @@ -74,7 +74,11 @@ export const Destination = ({ name, booth }) => { return label ? ( <>{label} ) : ( - + {T.translate("sponsor_reports_page.destination_booth_fallback")} ); diff --git a/src/components/sponsors/reports/PivotTree.js b/src/components/sponsors/reports/PivotTree.js index 27220c87a..01d07c72e 100644 --- a/src/components/sponsors/reports/PivotTree.js +++ b/src/components/sponsors/reports/PivotTree.js @@ -26,8 +26,7 @@ const Leaf = ({ rows }) => ( key={row.module?.id ?? i} direction="row" spacing={1} - alignItems="center" - sx={{ flexWrap: "wrap" }} + sx={{ alignItems: "center", flexWrap: "wrap" }} > {row.module?.component_name || @@ -65,8 +64,7 @@ const PivotTree = ({ nodes, summitId, depth = 0, maxDepth }) => ( {node.axisId === "sponsor" && ( - + {icon && ( {title} {subtitle && ( - + {subtitle} )} diff --git a/src/components/sponsors/reports/UnpaidChargesBySponsor.js b/src/components/sponsors/reports/UnpaidChargesBySponsor.js index 0862b27b0..c9046568f 100644 --- a/src/components/sponsors/reports/UnpaidChargesBySponsor.js +++ b/src/components/sponsors/reports/UnpaidChargesBySponsor.js @@ -419,7 +419,7 @@ const UnpaidChargesBySponsor = ({ key={group.sponsorId} expanded={expandedSponsors.has(group.sponsorId)} onChange={() => toggleSponsor(group.sponsorId)} - TransitionProps={{ unmountOnExit: true }} + slotProps={{ transition: { unmountOnExit: true } }} > }> diff --git a/src/components/summit-event-bulk-actions/summit-event-bulk-editor-form.js b/src/components/summit-event-bulk-actions/summit-event-bulk-editor-form.js index e9c06cf85..86732a2f7 100644 --- a/src/components/summit-event-bulk-actions/summit-event-bulk-editor-form.js +++ b/src/components/summit-event-bulk-actions/summit-event-bulk-editor-form.js @@ -13,9 +13,9 @@ import React from "react"; import T from "i18n-react/dist/i18n-react"; import Swal from "sweetalert2"; -import DateTimePicker from "openstack-uicore-foundation/lib/components/inputs/datetimepicker" -import SummitVenuesSelect from "openstack-uicore-foundation/lib/components/inputs/summit-venues-select" -import Input from "openstack-uicore-foundation/lib/components/inputs/text-input" +import DateTimePicker from "openstack-uicore-foundation/lib/components/inputs/datetimepicker"; +import SummitVenuesSelect from "openstack-uicore-foundation/lib/components/inputs/summit-venues-select"; +import Input from "openstack-uicore-foundation/lib/components/inputs/text-input"; import Dropdown from "openstack-uicore-foundation/lib/components/inputs/dropdown"; import { epochToMomentTimeZone } from "openstack-uicore-foundation/lib/utils/methods"; import moment from "moment-timezone"; @@ -451,11 +451,6 @@ class SummitEventBulkEditorForm extends React.Component {
@@ -478,11 +478,6 @@ class SummitEventBulkEditorForm extends React.Component { id="end_date" format={{ date: "YYYY-MM-DD", time: "HH:mm" }} timeConstraints={{ hours: { min: 7, max: 22 } }} - inputProps={{ - placeholder: T.translate( - "bulk_actions_page.placeholders.end_date" - ) - }} timezone={currentSummit.time_zone.name} value={epochToMomentTimeZone( currentBulkEndDate, @@ -497,6 +492,11 @@ class SummitEventBulkEditorForm extends React.Component { }} onChange={this.handleChangeBulkEndDate} className="bulk-edit-date-picker" + inputProps={{ + placeholder: T.translate( + "bulk_actions_page.placeholders.end_date" + ) + }} />
diff --git a/src/components/summit-event-bulk-actions/summit-event-bulk-editor-item.js b/src/components/summit-event-bulk-actions/summit-event-bulk-editor-item.js index a56b1cd34..2db1406a0 100644 --- a/src/components/summit-event-bulk-actions/summit-event-bulk-editor-item.js +++ b/src/components/summit-event-bulk-actions/summit-event-bulk-editor-item.js @@ -12,8 +12,8 @@ * */ import React from "react"; import { FormGroup, FormControl } from "react-bootstrap"; -import DateTimePicker from "openstack-uicore-foundation/lib/components/inputs/datetimepicker" -import SummitVenuesSelect from "openstack-uicore-foundation/lib/components/inputs/summit-venues-select" +import DateTimePicker from "openstack-uicore-foundation/lib/components/inputs/datetimepicker"; +import SummitVenuesSelect from "openstack-uicore-foundation/lib/components/inputs/summit-venues-select"; import Dropdown from "openstack-uicore-foundation/lib/components/inputs/dropdown"; import { SummitEvent } from "openstack-uicore-foundation/lib/models"; import moment from "moment-timezone"; @@ -309,11 +309,6 @@ class SummitEventBulkEditorItem extends React.Component { @@ -334,11 +334,6 @@ class SummitEventBulkEditorItem extends React.Component { id="end_date" format={{ date: "YYYY-MM-DD", time: "HH:mm" }} timeConstraints={{ hours: { min: 7, max: 22 } }} - inputProps={{ - placeholder: T.translate( - "bulk_actions_page.placeholders.end_date" - ) - }} timezone={currentSummit.time_zone.name} validation={{ after: @@ -348,6 +343,11 @@ class SummitEventBulkEditorItem extends React.Component { onChange={this.onTimeLocalChanged} value={this.getFormattedTime(event.end_date)} className="bulk-edit-date-picker" + inputProps={{ + placeholder: T.translate( + "bulk_actions_page.placeholders.end_date" + ) + }} /> diff --git a/src/index.js b/src/index.js index 0be5b3a68..8f9aa63b0 100644 --- a/src/index.js +++ b/src/index.js @@ -12,7 +12,7 @@ * */ import React from "react"; -import ReactDOM from "react-dom"; +import { createRoot } from "react-dom/client"; import { Provider } from "react-redux"; import { PersistGate } from "redux-persist/es/integration/react"; import { GlobalConfirmDialog } from "openstack-uicore-foundation/lib/components/mui/show-confirm-dialog"; @@ -30,7 +30,9 @@ const onBeforeLift = () => { console.log("reading state ..."); }; -ReactDOM.render( +const container = document.querySelector("#root"); +const root = createRoot(container); +root.render( @@ -40,6 +42,5 @@ ReactDOM.render( - , - document.querySelector("#root") + ); diff --git a/src/pages/admin_access/admin-access-form-popup.js b/src/pages/admin_access/admin-access-form-popup.js index 686e6a21f..cf1df274c 100644 --- a/src/pages/admin_access/admin-access-form-popup.js +++ b/src/pages/admin_access/admin-access-form-popup.js @@ -28,13 +28,7 @@ const AdminAccessFormPopup = ({ entity, errors, onClose, onSave }) => { }; return ( - + diff --git a/src/pages/attendees/summit-attendees-list-page.js b/src/pages/attendees/summit-attendees-list-page.js index d5e0e4fa2..77954345e 100644 --- a/src/pages/attendees/summit-attendees-list-page.js +++ b/src/pages/attendees/summit-attendees-list-page.js @@ -16,13 +16,13 @@ import { connect } from "react-redux"; import T from "i18n-react/dist/i18n-react"; import Swal from "sweetalert2"; import { Pagination } from "react-bootstrap"; -import Dropdown from "openstack-uicore-foundation/lib/components/inputs/dropdown" -import Input from "openstack-uicore-foundation/lib/components/inputs/text-input" -import FreeTextSearch from "openstack-uicore-foundation/lib/components/free-text-search" -import SelectableTable from "openstack-uicore-foundation/lib/components/table-selectable" -import DateTimePicker from "openstack-uicore-foundation/lib/components/inputs/datetimepicker" -import TagInput from "openstack-uicore-foundation/lib/components/inputs/tag-input" -import CompanyInput from "openstack-uicore-foundation/lib/components/inputs/company-input" +import Dropdown from "openstack-uicore-foundation/lib/components/inputs/dropdown"; +import Input from "openstack-uicore-foundation/lib/components/inputs/text-input"; +import FreeTextSearch from "openstack-uicore-foundation/lib/components/free-text-search"; +import SelectableTable from "openstack-uicore-foundation/lib/components/table-selectable"; +import DateTimePicker from "openstack-uicore-foundation/lib/components/inputs/datetimepicker"; +import TagInput from "openstack-uicore-foundation/lib/components/inputs/tag-input"; +import CompanyInput from "openstack-uicore-foundation/lib/components/inputs/company-input"; import TicketTypesInput from "openstack-uicore-foundation/lib/components/inputs/ticket-types-input"; import { epochToMomentTimeZone } from "openstack-uicore-foundation/lib/utils/methods"; import { SegmentedControl } from "segmented-control"; @@ -1039,11 +1039,6 @@ class SummitAttendeeListPage extends React.Component { this.handleCheckInDate(ev, false)} value={epochToMomentTimeZone( @@ -1051,6 +1046,11 @@ class SummitAttendeeListPage extends React.Component { currentSummit.time_zone_id )} className="event-list-date-picker" + inputProps={{ + placeholder: T.translate( + "attendee_list.placeholders.checkin_date_from" + ) + }} />
this.handleCheckInDate(ev, true)} value={epochToMomentTimeZone( @@ -1072,6 +1067,11 @@ class SummitAttendeeListPage extends React.Component { currentSummit.time_zone_id )} className="event-list-date-picker" + inputProps={{ + placeholder: T.translate( + "attendee_list.placeholders.checkin_date_to" + ) + }} />
@@ -1135,7 +1135,6 @@ class SummitAttendeeListPage extends React.Component { {attendees.length === 0 && (
{T.translate("attendee_list.no_attendees")}
)} -
- {attendees.length > 0 && (
{selectedCount > 0 && ( diff --git a/src/pages/companies/edit-company-page.js b/src/pages/companies/edit-company-page.js index 75660f2a9..204c7a2e8 100644 --- a/src/pages/companies/edit-company-page.js +++ b/src/pages/companies/edit-company-page.js @@ -17,7 +17,7 @@ import T from "i18n-react/dist/i18n-react"; import { Breadcrumb } from "react-breadcrumbs"; import { FormikProvider, useFormik } from "formik"; import * as yup from "yup"; -import { Box, Button, Grid2 } from "@mui/material"; +import { Box, Button, Grid } from "@mui/material"; import AddIcon from "@mui/icons-material/Add"; import CompanyForm from "../../components/forms/company-form"; import { @@ -123,17 +123,17 @@ const EditCompanyPage = ({ return (
- - +

{title} {T.translate("edit_company.company")}

-
+ {initialEntity?.id > 0 && ( - + - + )} -
+
- - +
diff --git a/src/pages/emails/email-log-list-page.js b/src/pages/emails/email-log-list-page.js index aa9ec3d91..1cd283e81 100644 --- a/src/pages/emails/email-log-list-page.js +++ b/src/pages/emails/email-log-list-page.js @@ -17,7 +17,7 @@ import T from "i18n-react/dist/i18n-react"; import { Box, FormControl, - Grid2, + Grid, InputLabel, MenuItem, OutlinedInput, @@ -162,7 +162,7 @@ const SentEmailListPage = ({ return (

{T.translate("email_logs.email_list")}

- - + {totalEmails} {T.translate("emails.emails")} - - + - + - + - - - + + + {T.translate("email_logs.select_fields")} @@ -228,10 +224,9 @@ const SentEmailListPage = ({ ))} - + {emails.length === 0 &&
{T.translate("emails.no_emails")}
} - {emails.length > 0 && ( - function MockSelect({ name, children, disabled }) { + () => { + // MUI v9 MenuItems throw outside a Menu/MenuList + const { MenuList } = jest.requireActual("@mui/material"); + return function MockSelect({ name, children, disabled }) { return (
- {children} + {children}
); - } + }; + } ); jest.mock( diff --git a/src/pages/events/components/event-type-dialog.js b/src/pages/events/components/event-type-dialog.js index f2f15352c..576f77510 100644 --- a/src/pages/events/components/event-type-dialog.js +++ b/src/pages/events/components/event-type-dialog.js @@ -28,7 +28,7 @@ import DialogActions from "@mui/material/DialogActions"; import DialogContent from "@mui/material/DialogContent"; import DialogTitle from "@mui/material/DialogTitle"; import Divider from "@mui/material/Divider"; -import Grid2 from "@mui/material/Grid2"; +import Grid from "@mui/material/Grid"; import IconButton from "@mui/material/IconButton"; import InputLabel from "@mui/material/InputLabel"; import MenuItem from "@mui/material/MenuItem"; @@ -211,13 +211,7 @@ const EventTypeDialog = ({ )} ${T.translate("edit_event_type.event_type")}`; return ( - + {title}
diff --git a/src/pages/events/event-category-list-page.js b/src/pages/events/event-category-list-page.js index 26793fb40..7d80afb74 100644 --- a/src/pages/events/event-category-list-page.js +++ b/src/pages/events/event-category-list-page.js @@ -14,7 +14,7 @@ import React, { useEffect, useState } from "react"; import { connect } from "react-redux"; import T from "i18n-react/dist/i18n-react"; -import { Box, Button, Grid2 } from "@mui/material"; +import { Box, Button, Grid } from "@mui/material"; import AddIcon from "@mui/icons-material/Add"; import MuiTableSortable from "openstack-uicore-foundation/lib/components/mui/sortable-table"; import SummitsDropdown from "openstack-uicore-foundation/lib/components/mui/summits-dropdown"; @@ -78,7 +78,7 @@ const EventCategoryListPage = ({ return (

{T.translate("event_category_list.event_category_list")}

- - + - - + + - - + - - + + - - + + {eventCategories.length === 0 && (
diff --git a/src/pages/events/summit-event-list-page/components/ImportMUXModal/index.jsx b/src/pages/events/summit-event-list-page/components/ImportMUXModal/index.jsx index a2f6703eb..338ede2bb 100644 --- a/src/pages/events/summit-event-list-page/components/ImportMUXModal/index.jsx +++ b/src/pages/events/summit-event-list-page/components/ImportMUXModal/index.jsx @@ -7,7 +7,7 @@ import DialogActions from "@mui/material/DialogActions"; import DialogContent from "@mui/material/DialogContent"; import DialogTitle from "@mui/material/DialogTitle"; import Divider from "@mui/material/Divider"; -import Grid2 from "@mui/material/Grid2"; +import Grid from "@mui/material/Grid"; import IconButton from "@mui/material/IconButton"; import TextField from "@mui/material/TextField"; import Tooltip from "@mui/material/Tooltip"; @@ -64,13 +64,7 @@ const ImportMUXModal = ({ show, onClose, onImport }) => { }; return ( - + { - - + + { fullWidth size="small" /> - - + + { fullWidth size="small" /> - - + + { fullWidth size="small" /> - - + + diff --git a/src/pages/events/summit-event-list-page/components/ImportModal/index.jsx b/src/pages/events/summit-event-list-page/components/ImportModal/index.jsx index 853b0b6b8..8a7876177 100644 --- a/src/pages/events/summit-event-list-page/components/ImportModal/index.jsx +++ b/src/pages/events/summit-event-list-page/components/ImportModal/index.jsx @@ -46,13 +46,7 @@ const ImportModal = ({ show, onClose, onImport }) => { }; return ( - + 1 ? parseInt(parts[1]) : 0; } isReportByPresentation(reportType) { - let parts = reportType.split("_"); + const parts = reportType.split("_"); return parts[0] === "PRESENTATION"; } @@ -68,7 +69,7 @@ class SummitPresentationsVotesPage extends React.Component { end_presentation_attendee_vote_date, term } = this.state; - let filters = []; + const filters = []; if (term !== "") { const escapedTerm = escapeFilterValue(term); if (this.isReportByPresentation(reportType)) @@ -114,15 +115,27 @@ class SummitPresentationsVotesPage extends React.Component { } handleChangeReportType(ev) { - const { value, id } = ev.target; + const { value } = ev.target; this.props.clearVotesReport(); this.setState({ ...this.state, current_report_type: value }); - let filters = this.buildExtraFilters(value); + const filters = this.buildExtraFilters(value); if (this.isReportByPresentation(value)) { - this.props.getPresentationsVotes(1, 10, "votes_count", 0, filters); + this.props.getPresentationsVotes( + 1, + DEFAULT_PER_PAGE, + "votes_count", + 0, + filters + ); return; } - this.props.getAttendeeVotes(1, 10, "presentation_votes_count", 0, filters); + this.props.getAttendeeVotes( + 1, + DEFAULT_PER_PAGE, + "presentation_votes_count", + 0, + filters + ); } handlePageChange(page) { @@ -142,7 +155,7 @@ class SummitPresentationsVotesPage extends React.Component { ); } - handleSort(index, key, dir, func) { + handleSort(index, key, dir) { const { page, perPage } = this.props; const { current_report_type } = this.state; const filters = this.buildExtraFilters(current_report_type); @@ -187,7 +200,7 @@ class SummitPresentationsVotesPage extends React.Component { } errors[id] = ""; - let newState = { ...this.state, errors }; + const newState = { ...this.state, errors }; newState[`${id}`] = value; @@ -197,15 +210,21 @@ class SummitPresentationsVotesPage extends React.Component { handleSearch(term) { const { order, orderDir } = this.props; const { current_report_type } = this.state; - this.setState({ ...this.state, term: term }, () => { + this.setState({ ...this.state, term }, () => { const filters = this.buildExtraFilters(current_report_type); if (this.isReportByPresentation(current_report_type)) { - this.props.getPresentationsVotes(1, 10, order, orderDir, filters); + this.props.getPresentationsVotes( + 1, + DEFAULT_PER_PAGE, + order, + orderDir, + filters + ); return; } this.props.getAttendeeVotes( 1, - 10, + DEFAULT_PER_PAGE, order === "votes_count" ? "presentation_votes_count" : order, orderDir, filters @@ -231,7 +250,7 @@ class SummitPresentationsVotesPage extends React.Component { current_report_type } = this.state; - let columns = this.isReportByPresentation(current_report_type) + const columns = this.isReportByPresentation(current_report_type) ? [ { columnKey: "id", value: T.translate("general.id"), sortable: true }, { @@ -271,15 +290,15 @@ class SummitPresentationsVotesPage extends React.Component { }; if (!currentSummit.id) return
; - let byPresentationOptions = currentSummit.track_groups.map((tg) => ({ + const byPresentationOptions = currentSummit.track_groups.map((tg) => ({ label: `View by Presentation for ${tg.name}`, value: `PRESENTATION_${tg.id}` })); - let byAttendeeOptions = currentSummit.track_groups.map((tg) => ({ + const byAttendeeOptions = currentSummit.track_groups.map((tg) => ({ label: `View by Attendee for ${tg.name}`, value: `ATTENDEE_${tg.id}` })); - let reportTypeDDL = [ + const reportTypeDDL = [ { label: "-- SELECT A REPORT TYPE --", value: "" }, ...byPresentationOptions, ...byAttendeeOptions @@ -303,8 +322,8 @@ class SummitPresentationsVotesPage extends React.Component { : T.translate("presentation_votes_page.attendees_vote_list")}{" "} ({totalItems}) -
-
+
+
-
+
-
-
-
-
+
+
+
+
-
+
-
+
-
+
{ )}`; return ( - + {title} { autoComplete="off" > - - + + {T.translate("media_file_type.name")} * @@ -109,8 +103,8 @@ const MediaFileTypeDialog = ({ entity: initialEntity, onClose, onSave }) => { fullWidth required /> - - + + {T.translate("media_file_type.description")} @@ -123,8 +117,8 @@ const MediaFileTypeDialog = ({ entity: initialEntity, onClose, onSave }) => { multiline rows={3} /> - - + + {T.translate("media_file_type.allowed_extensions_input")} @@ -137,8 +131,8 @@ const MediaFileTypeDialog = ({ entity: initialEntity, onClose, onSave }) => { multiline rows={2} /> - - + + diff --git a/src/pages/orders/purchase-order-list-page.js b/src/pages/orders/purchase-order-list-page.js index c5df9c4ae..e813ff9d8 100644 --- a/src/pages/orders/purchase-order-list-page.js +++ b/src/pages/orders/purchase-order-list-page.js @@ -14,10 +14,10 @@ import React from "react"; import { connect } from "react-redux"; import T from "i18n-react/dist/i18n-react"; import { Pagination } from "react-bootstrap"; -import FreeTextSearch from "openstack-uicore-foundation/lib/components/free-text-search" -import Dropdown from "openstack-uicore-foundation/lib/components/inputs/dropdown" -import DateTimePicker from "openstack-uicore-foundation/lib/components/inputs/datetimepicker" -import CompanyInput from "openstack-uicore-foundation/lib/components/inputs/company-input" +import FreeTextSearch from "openstack-uicore-foundation/lib/components/free-text-search"; +import Dropdown from "openstack-uicore-foundation/lib/components/inputs/dropdown"; +import DateTimePicker from "openstack-uicore-foundation/lib/components/inputs/datetimepicker"; +import CompanyInput from "openstack-uicore-foundation/lib/components/inputs/company-input"; import Table from "openstack-uicore-foundation/lib/components/table"; import { epochToMomentTimeZone } from "openstack-uicore-foundation/lib/utils/methods"; import { SegmentedControl } from "segmented-control"; @@ -423,11 +423,6 @@ class PurchaseOrderListPage extends React.Component { this.handleChangeDateFilter(ev, false)} value={epochToMomentTimeZone( @@ -435,17 +430,17 @@ class PurchaseOrderListPage extends React.Component { currentSummit.time_zone_id )} className="event-list-date-picker" + inputProps={{ + placeholder: T.translate( + "purchase_order_list.placeholders.purchased_from" + ) + }} />
this.handleChangeDateFilter(ev, true)} value={epochToMomentTimeZone( @@ -453,6 +448,11 @@ class PurchaseOrderListPage extends React.Component { currentSummit.time_zone_id )} className="event-list-date-picker" + inputProps={{ + placeholder: T.translate( + "purchase_order_list.placeholders.purchased_to" + ) + }} />
@@ -473,11 +473,9 @@ class PurchaseOrderListPage extends React.Component {
)}
- {purchaseOrders.length === 0 && (
{T.translate("purchase_order_list.no_orders")}
)} - {purchaseOrders.length > 0 && (
- - +

{title} {T.translate("edit_schedule_settings.schedule_settings")}

-
+ {entity.id > 0 && ( - + - + )} -
+
{currentSummit && ( - - +

{title} {T.translate("edit_selection_plan.selection_plan")}

-
+ {entity?.id > 0 && ( - + history.push( @@ -89,12 +89,12 @@ const EditSelectionPlanPage = ({ ) } /> - + )} -
+
- @@ -106,7 +106,7 @@ const EditSelectionPlanPage = ({ > {T.translate("general.save")} - + ); }; diff --git a/src/pages/signage/index.js b/src/pages/signage/index.js index af058ff3c..a84e0effe 100644 --- a/src/pages/signage/index.js +++ b/src/pages/signage/index.js @@ -1,4 +1,4 @@ -/** +/* * * Copyright 2017 OpenStack Foundation * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -230,13 +230,13 @@ const SignagePage = ({ setJumpDate(ev.target.value.unix())} value={epochToMomentTimeZone(jumpDate, summit.time_zone_id)} disabled={!locationId} + inputProps={{ + placeholder: T.translate("signage.placeholders.date") + }} /> - - + + - - + + - - + + diff --git a/src/pages/sponsors-global/page-templates/page-template-popup/module-clone-control.js b/src/pages/sponsors-global/page-templates/page-template-popup/module-clone-control.js index 4748584be..10350d381 100644 --- a/src/pages/sponsors-global/page-templates/page-template-popup/module-clone-control.js +++ b/src/pages/sponsors-global/page-templates/page-template-popup/module-clone-control.js @@ -72,7 +72,7 @@ const ModuleCloneControl = ({ - - - + + + {extraQuestions.length === 0 && (
{T.translate("edit_sponsor.no_extra_questions")}
)} @@ -215,7 +207,7 @@ const SponsorExtraQuestions = ({ } /> )} -
+
{questionToDelete && ( {formik.values.addons.map((addon, index) => ( - - {editingRow === index ? ( - + {`${formik.values.addons[index].type}`} )} - - + {`${formik.values.addons[index].name}`} )} - - + + {editingRow !== index && ( <> - - - + - + )} - - + + ))} {!formik.errors.addons && typeof formik.errors.addons === "string" && ( - + {formik.errors.addons} )} - - {T.translate("edit_sponsor.addon_type")} - + - - + - - + + - + {formik.errors.newAddon && typeof formik.errors.newAddon === "string" && ( - + {formik.errors.newAddon} )} - + diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-general-form/sponsor-header.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-general-form/sponsor-header.js index e29b5935c..fb13f5863 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-general-form/sponsor-header.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-general-form/sponsor-header.js @@ -18,7 +18,7 @@ import { Button, Checkbox, Divider, - Grid2, + Grid, Typography } from "@mui/material"; @@ -40,38 +40,38 @@ const SponsorHeader = ({ sponsor, onSave }) => { return ( - - + + {T.translate("edit_sponsor.general_information")} - - + + - - + {T.translate("edit_sponsor.sponsor_name")} - - {sponsor.company?.name} - + + {sponsor.company?.name} + - - + {T.translate("edit_sponsor.sponsor_address")} - - + + {[ sponsor.company?.city, sponsor.company?.state, @@ -88,20 +88,20 @@ const SponsorHeader = ({ sponsor, onSave }) => { )} - - + + - - + - - + { checked={isPublished} disabled={isSaving} onChange={() => setIsPublished(!isPublished)} - inputProps={{ "aria-labelledby": "sponsor-is-published-label" }} + slotProps={{ + input: { "aria-labelledby": "sponsor-is-published-label" } + }} /> - - + + ); }; diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-general-form/sponsorship.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-general-form/sponsorship.js index 0e3f81c19..6e852a872 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-general-form/sponsorship.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-general-form/sponsorship.js @@ -13,7 +13,7 @@ import React, { useState } from "react"; import T from "i18n-react/dist/i18n-react"; -import { Box, Button, Grid2, Typography } from "@mui/material"; +import { Box, Button, Grid, Typography } from "@mui/material"; import AddIcon from "@mui/icons-material/Add"; import MuiTable from "openstack-uicore-foundation/lib/components/mui/table"; import AddTierPopup from "./add-tier-popup"; @@ -140,8 +140,8 @@ const Sponsorship = ({ return ( <> - - + )} - - + + {showAddTierPopup && ( { minRows={4} value={text} onChange={(ev) => setText(ev.target.value)} - inputProps={{ maxLength: TEXT_MAX_LENGTH_1024 }} + slotProps={{ htmlInput: { maxLength: TEXT_MAX_LENGTH_1024 } }} helperText={`${text.length}/${TEXT_MAX_LENGTH_1024}`} /> diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/__tests__/sponsor-pages-tab.test.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/__tests__/sponsor-pages-tab.test.js index b3e2a6cf3..859333ebb 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/__tests__/sponsor-pages-tab.test.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/__tests__/sponsor-pages-tab.test.js @@ -205,10 +205,11 @@ describe("SponsorPagesTab", () => { } ); - const editButton = screen.getByTestId("EditIcon").closest("button"); - await act(async () => { - await userEvent.click(editButton); - }); + // open the row actions menu first: React 18 renders it only after the click settles + await userEvent.click(screen.getByTestId("row-actions-menu-trigger")); + await userEvent.click( + await screen.findByRole("menuitem", { name: "general.edit" }) + ); expect(getSponsorCustomizedPage).toHaveBeenCalledWith(1); await waitFor(() => { @@ -355,10 +356,11 @@ describe("SponsorPagesTab", () => { } ); - const editButton = screen.getByTestId("EditIcon").closest("button"); - await act(async () => { - await userEvent.click(editButton); - }); + // open the row actions menu first: React 18 renders it only after the click settles + await userEvent.click(screen.getByTestId("row-actions-menu-trigger")); + await userEvent.click( + await screen.findByRole("menuitem", { name: "general.edit" }) + ); await waitFor(() => { expect(screen.getByTestId("page-template-popup")).toBeInTheDocument(); diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js index e1149c856..fac2567cf 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/components/add-sponsor-page-template-popup/index.js @@ -25,7 +25,7 @@ import { DialogTitle, Divider, FormControlLabel, - Grid2, + Grid, IconButton, Typography } from "@mui/material"; @@ -196,15 +196,9 @@ const AddSponsorPageTemplatePopup = ({ ]; return ( - + - + {T.translate("edit_sponsor.pages_tab.add_page_using_template")} - + - - - + + - + {selectedPages.length}{" "} {T.translate("edit_sponsor.pages_tab.items_selected")} - - - - + + + + {" "} {T.translate("general.sort_by")} - - + + - - - + + + {showPages.length > 0 && ( diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-purchases-tab/sponsor-order-details.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-purchases-tab/sponsor-order-details.js index d5e3b4a74..24f34b896 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-purchases-tab/sponsor-order-details.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-purchases-tab/sponsor-order-details.js @@ -14,7 +14,7 @@ import React, { useEffect } from "react"; import { connect } from "react-redux"; import T from "i18n-react/dist/i18n-react"; -import { Box, Card, CardContent, Grid2, Typography } from "@mui/material"; +import { Box, Card, CardContent, Grid, Typography } from "@mui/material"; import { ListCard } from "openstack-uicore-foundation/lib/components/mui/cards"; import SponsorOrderGrid from "openstack-uicore-foundation/lib/components/mui/sponsor-order-grid"; import { @@ -137,32 +137,32 @@ const SponsorOrderDetails = ({ {T.translate("edit_sponsor.purchase_tab.order_details.order")}{" "} {currentOrder.number} - - + + - - + + - - + + - - + + - - + + - - + + ); }; diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-users-list-per-sponsor/components/new-user-popup.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-users-list-per-sponsor/components/new-user-popup.js index 4948d5568..2e53b2715 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-users-list-per-sponsor/components/new-user-popup.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-users-list-per-sponsor/components/new-user-popup.js @@ -60,13 +60,7 @@ const NewUserPopup = ({ }); return ( - + { autoComplete="off" > - - + + - - + + - - + + - - + + - - + + {T.translate("sponsor_users.edit_user.access")} diff --git a/src/pages/sponsors/sponsor-reports/reports-landing-page/index.js b/src/pages/sponsors/sponsor-reports/reports-landing-page/index.js index da93d75d9..d08e960b4 100644 --- a/src/pages/sponsors/sponsor-reports/reports-landing-page/index.js +++ b/src/pages/sponsors/sponsor-reports/reports-landing-page/index.js @@ -18,7 +18,7 @@ import { Card, CardActionArea, CardContent, - Grid2, + Grid, Typography } from "@mui/material"; @@ -43,9 +43,9 @@ const CARDS = [ const ReportsLandingPage = ({ match }) => (

{T.translate("sponsor_reports_page.landing_title")}

- + {CARDS.map((card) => ( - + ( {T.translate(card.titleKey)} - + {T.translate(card.descKey)} - + ))} - +
); diff --git a/src/pages/sponsors/sponsor-reports/sponsor-asset-drilldown-page/index.js b/src/pages/sponsors/sponsor-reports/sponsor-asset-drilldown-page/index.js index e7eb415ee..2ffc01233 100644 --- a/src/pages/sponsors/sponsor-reports/sponsor-asset-drilldown-page/index.js +++ b/src/pages/sponsors/sponsor-reports/sponsor-asset-drilldown-page/index.js @@ -32,7 +32,7 @@ import { Button, Card, CardContent, - Grid2, + Grid, Stack, Typography } from "@mui/material"; @@ -160,10 +160,10 @@ const SponsorAssetDrilldownPage = ({ gap: 1 }} > - + - + {sponsor.name} @@ -209,9 +209,9 @@ const SponsorAssetDrilldownPage = ({ {T.translate("sponsor_reports_page.download_csv")} - + {section.modules?.map((row) => ( - + - + ))} - + ))} diff --git a/src/pages/sponsors/sponsor-reports/sponsor-asset-report-page/index.js b/src/pages/sponsors/sponsor-reports/sponsor-asset-report-page/index.js index a7f72f03d..122c20dba 100644 --- a/src/pages/sponsors/sponsor-reports/sponsor-asset-report-page/index.js +++ b/src/pages/sponsors/sponsor-reports/sponsor-asset-report-page/index.js @@ -160,8 +160,7 @@ const SponsorAssetReportPage = ({ diff --git a/src/pages/sponsors/sponsor-users-list-page/components/__tests__/process-request-popup.test.js b/src/pages/sponsors/sponsor-users-list-page/components/__tests__/process-request-popup.test.js index 2fefdf50a..f80f1c90a 100644 --- a/src/pages/sponsors/sponsor-users-list-page/components/__tests__/process-request-popup.test.js +++ b/src/pages/sponsors/sponsor-users-list-page/components/__tests__/process-request-popup.test.js @@ -121,13 +121,17 @@ describe("ProcessRequestPopup", () => { } ); + // Flush the fetchSponsorByCompany microtask so the form reinitialises with + // sponsor_type=EXISTING before we click submit. + await act(async () => { + await Promise.resolve(); + }); + const processRequestButton = screen.getAllByText( "sponsor_users.process_request.save" )[0]; - await act(async () => { - await userEvent.click(processRequestButton); - }); + await userEvent.click(processRequestButton); expect(sponsorUsersActions.processSponsorUserRequest).toHaveBeenCalled(); expect(onCloseMock).toHaveBeenCalled(); }); diff --git a/src/pages/sponsors/sponsor-users-list-page/components/edit-user-popup/sponsor-user-form.js b/src/pages/sponsors/sponsor-users-list-page/components/edit-user-popup/sponsor-user-form.js index 549ef054e..baa640e0f 100644 --- a/src/pages/sponsors/sponsor-users-list-page/components/edit-user-popup/sponsor-user-form.js +++ b/src/pages/sponsors/sponsor-users-list-page/components/edit-user-popup/sponsor-user-form.js @@ -5,7 +5,7 @@ import { DialogActions, DialogContent, Divider, - Grid2 + Grid } from "@mui/material"; import T from "i18n-react"; import * as yup from "yup"; @@ -71,35 +71,35 @@ const SponsorUserForm = ({ user, summitId, userGroups, onSubmit }) => { autoComplete="off" > - - + + - - + + - - + + - + - + diff --git a/src/pages/sponsors/sponsor-users-list-page/components/process-request-form.js b/src/pages/sponsors/sponsor-users-list-page/components/process-request-form.js index d9898e442..052343936 100644 --- a/src/pages/sponsors/sponsor-users-list-page/components/process-request-form.js +++ b/src/pages/sponsors/sponsor-users-list-page/components/process-request-form.js @@ -5,7 +5,7 @@ import { DialogActions, DialogContent, Divider, - Grid2, + Grid, InputLabel, Typography } from "@mui/material"; @@ -118,58 +118,58 @@ const ProcessRequestForm = ({ request, userGroups, summit, onSubmit }) => { {T.translate("sponsor_users.process_request.request_details")} - - + + {T.translate("sponsor_users.process_request.request_time")} - - + + {request.created} - - + + - - + + {T.translate("sponsor_users.process_request.show")} - - + + {summit.name} - - + + - - + + {T.translate("sponsor_users.process_request.company")} - - + + {request.company_name} - - + + {T.translate("sponsor_users.process_request.new_user")} - - + + - - + + - - + + { } ]} /> - - + + { "sponsor_users.process_request.select_sponsor" )} /> - - + + { )} allowCreate /> - - + + {formik.values.sponsor_type === SPONSOR_USER_ASSIGNMENT_TYPE.NEW && ( <> diff --git a/src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js b/src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js index dcd903f26..024151bdc 100644 --- a/src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js +++ b/src/pages/sponsors/sponsor-users-list-page/components/sponsor-global-import-users-popup.js @@ -157,13 +157,7 @@ const SponsorGlobalImportUsersPopup = ({ }; return ( - + { }); return ( - + { )}`; return ( - + {title} { autoComplete="off" > - - + + {T.translate("edit_sponsorship.name")} * @@ -110,8 +104,8 @@ const SponsorshipDialog = ({ entity: initialEntity, onClose, onSave }) => { fullWidth required /> - - + + {T.translate("edit_sponsorship.label")} @@ -121,8 +115,8 @@ const SponsorshipDialog = ({ entity: initialEntity, onClose, onSave }) => { margin="none" fullWidth /> - - + + {T.translate("edit_sponsorship.size")} @@ -137,8 +131,8 @@ const SponsorshipDialog = ({ entity: initialEntity, onClose, onSave }) => { options={SIZE_OPTIONS_DDL} /> - - + + diff --git a/src/pages/summits/components/dashboard-stat-section.js b/src/pages/summits/components/dashboard-stat-section.js index 2aecf6853..1cb8c4554 100644 --- a/src/pages/summits/components/dashboard-stat-section.js +++ b/src/pages/summits/components/dashboard-stat-section.js @@ -1,7 +1,7 @@ import React from "react"; import PropTypes from "prop-types"; import Divider from "@mui/material/Divider"; -import Grid2 from "@mui/material/Grid2"; +import Grid from "@mui/material/Grid"; import DashboardSection from "./dashboard-section"; import SummitDashboardStat from "./summit-dashboard-stat"; @@ -17,13 +17,13 @@ function DashboardStatSection({ title, rows }) { return ( {i > 0 && } - + {group.map(({ title: label, stat: value }) => ( - + - + ))} - + ); })} diff --git a/src/pages/summits/components/summit-dashboard-stat.js b/src/pages/summits/components/summit-dashboard-stat.js index 1a72d9345..8b2a2054e 100644 --- a/src/pages/summits/components/summit-dashboard-stat.js +++ b/src/pages/summits/components/summit-dashboard-stat.js @@ -6,7 +6,7 @@ import Typography from "@mui/material/Typography"; function SummitDashboardStat({ label, value }) { return ( - + {label} diff --git a/src/pages/summits/summit-dashboard-page.js b/src/pages/summits/summit-dashboard-page.js index 6738cf045..776db57ac 100644 --- a/src/pages/summits/summit-dashboard-page.js +++ b/src/pages/summits/summit-dashboard-page.js @@ -17,7 +17,7 @@ import T from "i18n-react/dist/i18n-react"; import { Breadcrumb } from "react-breadcrumbs"; import Box from "@mui/material/Box"; import Container from "@mui/material/Container"; -import Grid2 from "@mui/material/Grid2"; +import Grid from "@mui/material/Grid"; import Stack from "@mui/material/Stack"; import Tab from "@mui/material/Tab"; import Tabs from "@mui/material/Tabs"; @@ -81,8 +81,8 @@ function SummitDashboardPage({ - - + + ))} - + {canEditSummit && ( - + - + )} - + ); } diff --git a/src/pages/tags/tags-popup.js b/src/pages/tags/tags-popup.js index f39f40cd2..de9b8683b 100644 --- a/src/pages/tags/tags-popup.js +++ b/src/pages/tags/tags-popup.js @@ -45,13 +45,7 @@ const TagsDialog = ({ onClose, onSave, initialData }) => { }; return ( - + {initialData?.id ? `${T.translate("general.edit")} ${T.translate("edit_tag.tag")}` diff --git a/src/pages/taxes/popup/tax-type-popup.js b/src/pages/taxes/popup/tax-type-popup.js index 96b27fb5d..29de39764 100644 --- a/src/pages/taxes/popup/tax-type-popup.js +++ b/src/pages/taxes/popup/tax-type-popup.js @@ -38,13 +38,7 @@ const TaxTypePopup = ({ }; return ( - + {title} {T.translate("edit_tax_type.tax_type")} diff --git a/src/pages/tickets/payment-profile/components/payment-profile-dialog.js b/src/pages/tickets/payment-profile/components/payment-profile-dialog.js index 2bec371ea..5d2f15070 100644 --- a/src/pages/tickets/payment-profile/components/payment-profile-dialog.js +++ b/src/pages/tickets/payment-profile/components/payment-profile-dialog.js @@ -8,7 +8,7 @@ import { DialogTitle, Button, Divider, - Grid2, + Grid, IconButton, InputAdornment, MenuItem, @@ -36,7 +36,7 @@ const InfoTooltip = ({ title }) => ( @@ -265,7 +265,6 @@ const PaymentProfileDialog = ({ disableEnforceFocus disableAutoFocus disableRestoreFocus - disableEscapeKeyDown={isSaving} > {title} @@ -282,8 +281,8 @@ const PaymentProfileDialog = ({ - - + + {T.translate("edit_payment_profile.application_type")} @@ -300,8 +299,8 @@ const PaymentProfileDialog = ({ ))} - - + + {T.translate("edit_payment_profile.provider")} @@ -312,15 +311,15 @@ const PaymentProfileDialog = ({ ))} - + - + - - + + } /> - + {formik.values.provider === "Stripe" && ( - + } /> - + )} {formik.values.provider === "LawPay" && ( - + {T.translate("edit_payment_profile.merchant_account_id")} @@ -363,10 +362,10 @@ const PaymentProfileDialog = ({ fullWidth variant="outlined" /> - + )} - + {T.translate("edit_payment_profile.live_secret_key")} - - + + {T.translate("edit_payment_profile.live_publishable_key")} - - + + {T.translate("edit_payment_profile.test_secret_key")} - - + + {T.translate("edit_payment_profile.test_publishable_key")} - - + + {formik.values.id !== 0 && formik.values.provider === "Stripe" && formik.values.application_type === "SponsorServices" && ( <> - +
{T.translate("edit_payment_profile.payment_type_fee")}
- - + {paymentFeeTypes.totalPaymentFeeTypes}{" "} {T.translate("edit_payment_profile.payment_type_fees")} - - + + {!showFeeTypeForm && ( - - + + )}
)} - + {totalTicketTypes} {T.translate("ticket_type_list.ticket_types")} - + { await selectTrack(); await clickSave(); - // disableEscapeKeyDown={true} while isSaving — onClose must not fire + // Escape calls onClose, which ignores it while isSaving await act(async () => { await userEvent.keyboard("{Escape}"); }); diff --git a/src/pages/track_chairs/components/track-chair-dialog.js b/src/pages/track_chairs/components/track-chair-dialog.js index a5d8c5bab..f592a2898 100644 --- a/src/pages/track_chairs/components/track-chair-dialog.js +++ b/src/pages/track_chairs/components/track-chair-dialog.js @@ -28,7 +28,7 @@ import { Divider, FormControl, FormHelperText, - Grid2, + Grid, IconButton, InputLabel, ListItemText, @@ -101,15 +101,9 @@ const TrackChairDialog = ({ entity, tracks, onSave, onClose }) => { const tracks_ddl = tracks.map((t) => ({ label: t.name, value: t.id })); return ( - + - {title} + {title} { autoComplete="off" > - - + + {T.translate("track_chairs.placeholders.select_track_chair")}{" "} * @@ -144,8 +138,8 @@ const TrackChairDialog = ({ entity, tracks, onSave, onClose }) => { )} disabled={entity?.id > 0} /> - - + + {T.translate("track_chairs.track")} * @@ -217,8 +211,8 @@ const TrackChairDialog = ({ entity, tracks, onSave, onClose }) => { {formik.errors.trackIds} )} - - + + diff --git a/testSetupFile.js b/testSetupFile.js index d4a2d5865..ea616f97c 100644 --- a/testSetupFile.js +++ b/testSetupFile.js @@ -8,30 +8,22 @@ global.TextDecoder = TextDecoder; // stub it to keep that out of test output. window.scrollTo = () => {}; -// Suppress console.error noise from known React 16 + MUI v6 incompatibilities: +// Suppress console.error noise from known jsdom/MUI incompatibilities: // 1. DOM nesting: AccordionSummary renders as