diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 43487a6..e5684e0 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -19,6 +19,16 @@ updates:
interval: weekly
open-pull-requests-limit: 10
groups:
+ # @mui/material and @mui/icons-material must move in lockstep (icons
+ # peer-depends on material), so group them — including majors — into a
+ # single PR. Listed before `web` so MUI deps land here, not there.
+ mui:
+ patterns:
+ - "@mui/*"
+ update-types:
+ - "major"
+ - "minor"
+ - "patch"
web:
patterns:
- "*"
diff --git a/web/package-lock.json b/web/package-lock.json
index 6d4167a..4d63a92 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -10,8 +10,8 @@
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
- "@mui/icons-material": "^7.3.1",
- "@mui/material": "^7.3.1",
+ "@mui/icons-material": "^9.1.1",
+ "@mui/material": "^9.1.1",
"@reduxjs/toolkit": "^2.11.2",
"@tanstack/react-query": "^5.101.0",
"axios": "^1.18.0",
@@ -1186,9 +1186,9 @@
}
},
"node_modules/@mui/core-downloads-tracker": {
- "version": "7.3.11",
- "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.11.tgz",
- "integrity": "sha512-a7I/b/nBTdXYz2cOSlEmkQ9WWE1x8FHpqMhFPp+Y1VPFxcOw91G5ELOHARQAGSPy5V+UCgJua6K/1x70bAtQPw==",
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-9.1.1.tgz",
+ "integrity": "sha512-AupmMICbdJHqAh6FfOMaaiiIr7dfEgZJn5DFfiPuGNrbs+ZZy9cD1APwO0TSVBz5j08MJEEY6n7iC76/2wjMEA==",
"license": "MIT",
"funding": {
"type": "opencollective",
@@ -1196,12 +1196,12 @@
}
},
"node_modules/@mui/icons-material": {
- "version": "7.3.11",
- "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.11.tgz",
- "integrity": "sha512-+hz5ilwHZ3djd5es3sCErLioqe/NhZcYTsV/TNXZAMdJdb23F4xzJjqnnZdnurc3S1+ietcssRNqieOhPQLZ7Q==",
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-9.1.1.tgz",
+ "integrity": "sha512-OXhm9DajemStb58AumM06DuPhHTa3XD36TFD4yf6WtJyNRO5DfEZbbnHlBg/US2Y2oOXwM/XurMTBOD6L/YYZw==",
"license": "MIT",
"dependencies": {
- "@babel/runtime": "^7.28.6"
+ "@babel/runtime": "^7.29.2"
},
"engines": {
"node": ">=14.0.0"
@@ -1211,7 +1211,7 @@
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
- "@mui/material": "^7.3.11",
+ "@mui/material": "^9.1.1",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
@@ -1222,22 +1222,22 @@
}
},
"node_modules/@mui/material": {
- "version": "7.3.11",
- "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.11.tgz",
- "integrity": "sha512-yq8bPc3LxOwKRWpcjRgDkYFmpM6aKlARfESTmOQcvLYFeJwtHte2tw6hJDrb8sk8wcvpDprHEHVaoUU0MslIkw==",
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/@mui/material/-/material-9.1.1.tgz",
+ "integrity": "sha512-Wv+gInjrpf99l1Q0oHe0eOWGTnlbkzs5nowClX65KCT/2fyPMwcbFEEkUsOHdpcHhB5UAbz/d7jlwt5ajWVvlA==",
"license": "MIT",
"dependencies": {
- "@babel/runtime": "^7.28.6",
- "@mui/core-downloads-tracker": "^7.3.11",
- "@mui/system": "^7.3.11",
- "@mui/types": "^7.4.12",
- "@mui/utils": "^7.3.11",
+ "@babel/runtime": "^7.29.2",
+ "@mui/core-downloads-tracker": "^9.1.1",
+ "@mui/system": "^9.1.1",
+ "@mui/types": "^9.1.1",
+ "@mui/utils": "^9.1.1",
"@popperjs/core": "^2.11.8",
"@types/react-transition-group": "^4.4.12",
"clsx": "^2.1.1",
"csstype": "^3.2.3",
"prop-types": "^15.8.1",
- "react-is": "^19.2.3",
+ "react-is": "^19.2.6",
"react-transition-group": "^4.4.5"
},
"engines": {
@@ -1250,7 +1250,7 @@
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
- "@mui/material-pigment-css": "^7.3.11",
+ "@mui/material-pigment-css": "^9.1.1",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
@@ -1271,13 +1271,13 @@
}
},
"node_modules/@mui/private-theming": {
- "version": "7.3.11",
- "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.11.tgz",
- "integrity": "sha512-9B+YKms0fRHbNrqp9tOT/DNbNnU5gyvJ1o3qAGXfq8GmZcbJnE3At9x07Zr/o0pkhzg4aDdwXVqe4+AcgtOCPA==",
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-9.1.1.tgz",
+ "integrity": "sha512-oH6c+d6sJ1CZT0Vg2/fHdUQ5zvo9Pn+f+WWk0tlQliHqqIRdN32DZ7UxjalW3LUj4OkHbdWR31biWuLxK9i7Cg==",
"license": "MIT",
"dependencies": {
- "@babel/runtime": "^7.28.6",
- "@mui/utils": "^7.3.11",
+ "@babel/runtime": "^7.29.2",
+ "@mui/utils": "^9.1.1",
"prop-types": "^15.8.1"
},
"engines": {
@@ -1298,12 +1298,12 @@
}
},
"node_modules/@mui/styled-engine": {
- "version": "7.3.10",
- "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.10.tgz",
- "integrity": "sha512-WxE9SiF8xskAQqGjsp0poXCkCqsoXFEsSr0HBXfApmGHR+DBnXRp+z46Vsltg4gpPM4Z96DeAQRpeAOnhNg7Ng==",
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-9.1.1.tgz",
+ "integrity": "sha512-neaYKdJfvEG54q8efHLJR7swpHG/gfSv9xGqW5iTSMsubD7yPCPFrhVBt284j1DOF3uZaaDJSHQL7gz6jGF21Q==",
"license": "MIT",
"dependencies": {
- "@babel/runtime": "^7.28.6",
+ "@babel/runtime": "^7.29.2",
"@emotion/cache": "^11.14.0",
"@emotion/serialize": "^1.3.3",
"@emotion/sheet": "^1.4.0",
@@ -1332,16 +1332,16 @@
}
},
"node_modules/@mui/system": {
- "version": "7.3.11",
- "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.11.tgz",
- "integrity": "sha512-7izwGWdNawAKpBKcRlx7f2gFnAAjmASBWvMcyX4YYEeLOFsbfGRbUYGInvnAcUeql3rPxI7F9Ft4oY2OLRz44g==",
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/@mui/system/-/system-9.1.1.tgz",
+ "integrity": "sha512-q+aqNa58QZUwmmyUvJKKrStrej+4BcWFw4M0Ug+zRylPIQgR64cqvBnE3QTfLZm4OXulydp8Hl3zwKxMayrdsA==",
"license": "MIT",
"dependencies": {
- "@babel/runtime": "^7.28.6",
- "@mui/private-theming": "^7.3.11",
- "@mui/styled-engine": "^7.3.10",
- "@mui/types": "^7.4.12",
- "@mui/utils": "^7.3.11",
+ "@babel/runtime": "^7.29.2",
+ "@mui/private-theming": "^9.1.1",
+ "@mui/styled-engine": "^9.1.1",
+ "@mui/types": "^9.1.1",
+ "@mui/utils": "^9.1.1",
"clsx": "^2.1.1",
"csstype": "^3.2.3",
"prop-types": "^15.8.1"
@@ -1372,12 +1372,12 @@
}
},
"node_modules/@mui/types": {
- "version": "7.4.12",
- "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.12.tgz",
- "integrity": "sha512-iKNAF2u9PzSIj40CjvKJWxFXJo122jXVdrmdh0hMYd+FR+NuJMkr/L88XwWLCRiJ5P1j+uyac25+Kp6YC4hu6w==",
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/@mui/types/-/types-9.1.1.tgz",
+ "integrity": "sha512-Zjt7u8wNvDg40rPTGoL+TnfkpuSKjwubsNSFRH1KAVZLcaV4I3AFNHIFbvH7p4F3alEibSbdd90xAgn5Rnfndg==",
"license": "MIT",
"dependencies": {
- "@babel/runtime": "^7.28.6"
+ "@babel/runtime": "^7.29.2"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
@@ -1389,17 +1389,17 @@
}
},
"node_modules/@mui/utils": {
- "version": "7.3.11",
- "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.11.tgz",
- "integrity": "sha512-XTjGnifwteg71/ij+0e7Y7d+hwyntMYP5wPoA/g2drdGH+Flkvjwy0OfrVpKBbaOvofq4zU/LIyUZyKgmWu18g==",
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-9.1.1.tgz",
+ "integrity": "sha512-qSNfnkzZMptaaWFFklpDf4NPJztgwsMDVfM/sSDt+wq4ssYSBhLYwwjuB6eS/+p2IUYbeRzHluzXbw0Zn7aI4A==",
"license": "MIT",
"dependencies": {
- "@babel/runtime": "^7.28.6",
- "@mui/types": "^7.4.12",
+ "@babel/runtime": "^7.29.2",
+ "@mui/types": "^9.1.1",
"@types/prop-types": "^15.7.15",
"clsx": "^2.1.1",
"prop-types": "^15.8.1",
- "react-is": "^19.2.3"
+ "react-is": "^19.2.6"
},
"engines": {
"node": ">=14.0.0"
@@ -3471,9 +3471,9 @@
}
},
"node_modules/react-is": {
- "version": "19.2.6",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.6.tgz",
- "integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==",
+ "version": "19.2.7",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.7.tgz",
+ "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==",
"license": "MIT"
},
"node_modules/react-redux": {
diff --git a/web/package.json b/web/package.json
index 22de8f8..6452980 100644
--- a/web/package.json
+++ b/web/package.json
@@ -13,8 +13,8 @@
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
- "@mui/icons-material": "^7.3.1",
- "@mui/material": "^7.3.1",
+ "@mui/icons-material": "^9.1.1",
+ "@mui/material": "^9.1.1",
"@reduxjs/toolkit": "^2.11.2",
"@tanstack/react-query": "^5.101.0",
"axios": "^1.18.0",
diff --git a/web/src/components/Sidebar.tsx b/web/src/components/Sidebar.tsx
index 086e282..617277b 100644
--- a/web/src/components/Sidebar.tsx
+++ b/web/src/components/Sidebar.tsx
@@ -106,7 +106,7 @@ export default function Sidebar() {
{item.icon}
{!isCollapsed && (
-
+
)}
);
diff --git a/web/src/pages/admin/customers/CustomerManagementPage.tsx b/web/src/pages/admin/customers/CustomerManagementPage.tsx
index 9248b98..f5ec909 100644
--- a/web/src/pages/admin/customers/CustomerManagementPage.tsx
+++ b/web/src/pages/admin/customers/CustomerManagementPage.tsx
@@ -27,7 +27,7 @@ import {
import SearchIcon from '@mui/icons-material/Search';
import AddIcon from '@mui/icons-material/Add';
import EditIcon from '@mui/icons-material/Edit';
-import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
+import ErrorOutlineIcon from '@mui/icons-material/ErrorOutlined';
import { toast } from 'react-toastify';
import {
customersApi,
diff --git a/web/src/pages/admin/dashboard/AdminDashboard.tsx b/web/src/pages/admin/dashboard/AdminDashboard.tsx
index 40289c4..bdf4578 100644
--- a/web/src/pages/admin/dashboard/AdminDashboard.tsx
+++ b/web/src/pages/admin/dashboard/AdminDashboard.tsx
@@ -34,7 +34,7 @@ import TimerIcon from '@mui/icons-material/Timer';
import DescriptionIcon from '@mui/icons-material/Description';
import WarningAmberIcon from '@mui/icons-material/WarningAmber';
import ReportIcon from '@mui/icons-material/Report';
-import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
+import ErrorOutlineIcon from '@mui/icons-material/ErrorOutlined';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
import { usePaginatedList } from '../../../hooks/usePaginatedList';
diff --git a/web/src/pages/admin/pricing-library/PricingLibraryPage.tsx b/web/src/pages/admin/pricing-library/PricingLibraryPage.tsx
index 95feec0..099c2a7 100644
--- a/web/src/pages/admin/pricing-library/PricingLibraryPage.tsx
+++ b/web/src/pages/admin/pricing-library/PricingLibraryPage.tsx
@@ -28,7 +28,7 @@ import {
import AddIcon from '@mui/icons-material/Add';
import EditIcon from '@mui/icons-material/Edit';
import DeleteIcon from '@mui/icons-material/Delete';
-import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
+import ErrorOutlineIcon from '@mui/icons-material/ErrorOutlined';
import { toast } from 'react-toastify';
import {
pricingLibraryApi,
diff --git a/web/src/pages/dashboard/Dashboard.tsx b/web/src/pages/dashboard/Dashboard.tsx
index 7f3383a..3728186 100644
--- a/web/src/pages/dashboard/Dashboard.tsx
+++ b/web/src/pages/dashboard/Dashboard.tsx
@@ -22,7 +22,7 @@ import DescriptionIcon from '@mui/icons-material/Description';
import HourglassTopIcon from '@mui/icons-material/HourglassTop';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import SendIcon from '@mui/icons-material/Send';
-import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
+import ErrorOutlineIcon from '@mui/icons-material/ErrorOutlined';
import Tooltip from '@mui/material/Tooltip';
import { proposalsApi, type ProposalListItem, type ProposalStats } from '../../lib/api/proposals';
import { QUERY_KEYS } from '../../constants/queryKeys';
diff --git a/web/src/pages/proposals/form/ProposalFormPage.tsx b/web/src/pages/proposals/form/ProposalFormPage.tsx
index 713f49f..2d1d6b9 100644
--- a/web/src/pages/proposals/form/ProposalFormPage.tsx
+++ b/web/src/pages/proposals/form/ProposalFormPage.tsx
@@ -267,12 +267,13 @@ export default function ProposalFormPage() {
required
placeholder="Search or type a customer name..."
slotProps={{
+ ...params.slotProps,
input: {
- ...params.InputProps,
+ ...params.slotProps.input,
endAdornment: (
<>
{customerLoading && }
- {params.InputProps.endAdornment}
+ {params.slotProps.input.endAdornment}
>
),
},
@@ -417,12 +418,13 @@ export default function ProposalFormPage() {
required
placeholder="Search by site code..."
slotProps={{
+ ...params.slotProps,
input: {
- ...params.InputProps,
+ ...params.slotProps.input,
endAdornment: (
<>
{siteLoading && }
- {params.InputProps.endAdornment}
+ {params.slotProps.input.endAdornment}
>
),
},
diff --git a/web/vitest.config.ts b/web/vitest.config.ts
index 4f6d395..e47388f 100644
--- a/web/vitest.config.ts
+++ b/web/vitest.config.ts
@@ -8,5 +8,13 @@ export default defineConfig({
globals: true,
setupFiles: ['./src/test/setup.ts'],
include: ['src/**/*.test.{ts,tsx}'],
+ server: {
+ deps: {
+ // MUI v9's ESM build (Transition.mjs) does a directory import of
+ // react-transition-group/TransitionGroupContext, which Node's native
+ // ESM loader can't resolve. Inline these so Vite resolves them.
+ inline: [/@mui\/material/, 'react-transition-group'],
+ },
+ },
},
});