Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

App router migration new relic configuration #1086

Open
wants to merge 32 commits into
base: next-js-migration
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
440bcb0
Add basic Root Layout
boodland Aug 19, 2024
78f94ae
Add metadata
boodland Aug 19, 2024
e4bffac
Add reference included by next
boodland Aug 19, 2024
844f412
Add comment to explain the default meta tags
boodland Aug 19, 2024
d857356
Add public testing page to check the migration
boodland Aug 19, 2024
c7148d3
Add basic Root Layout
boodland Aug 19, 2024
7f0deb9
Add metadata
boodland Aug 19, 2024
b6c1f22
Add reference included by next
boodland Aug 19, 2024
4f2d7c4
Add comment to explain the default meta tags
boodland Aug 19, 2024
a10db01
Add public testing page to check the migration
boodland Aug 19, 2024
7c20c78
Add new relic nextjs configuration
boodland Aug 19, 2024
2c6a7bc
Create new relic configuration file
boodland Aug 19, 2024
7e53126
Use new relic configuration
boodland Aug 19, 2024
fbc9686
Merge branch 'next-js-migration' into app-router-migration-root-layout
boodland Aug 30, 2024
b593d6f
Merge branch 'app-router-migration-root-layout' into app-router-migra…
boodland Aug 30, 2024
86241af
Remove non required file
boodland Aug 30, 2024
ceaa88e
Merge branch 'app-router-migration-root-layout' into app-router-migra…
boodland Aug 30, 2024
7753da2
Add basic Root Layout
boodland Aug 19, 2024
4955f46
Add metadata
boodland Aug 19, 2024
9e2bb39
Add reference included by next
boodland Aug 19, 2024
297f5c9
Add comment to explain the default meta tags
boodland Aug 19, 2024
23afe00
Add public testing page to check the migration
boodland Aug 19, 2024
39d2c87
Merge branch 'next-js-migration' into app-router-migration-new-relic-…
boodland Sep 12, 2024
5fd9223
App router migration google tag manager script (#1117)
boodland Sep 17, 2024
c076abd
Merge branch 'next-js-migration' into app-router-migration-new-relic-…
boodland Sep 18, 2024
4effeae
App router migration rollbar script (#1118)
boodland Sep 20, 2024
40496ab
App router migration opengraph metadata (#1120)
boodland Sep 20, 2024
24fc604
Merge branch 'next-js-migration' into app-router-migration-new-relic-…
boodland Sep 20, 2024
5d9708b
App router migration error boundary component (#1121)
boodland Sep 20, 2024
bf7c899
App router migration material UI configuration (#1122)
boodland Sep 20, 2024
db8dd34
App router migration analytics (#1123)
boodland Sep 20, 2024
a673cd7
Merge branch 'next-js-migration' into app-router-migration-new-relic-…
boodland Sep 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions app/ThemeRegistry.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { AppRouterCacheProvider } from '@mui/material-nextjs/v13-appRouter';
import CssBaseline from '@mui/material/CssBaseline';
import { ThemeProvider } from '@mui/material/styles';
import theme from '../styles/theme';

// This implementation is from mui integrations with nextjs app router
// see https://mui.com/material-ui/integrations/nextjs/#app-router
export default function ThemeRegistry({ children }: { children: React.ReactNode }) {
return (
<AppRouterCacheProvider>
<ThemeProvider theme={theme}>
<CssBaseline />
{children}
</ThemeProvider>
</AppRouterCacheProvider>
);
}
8 changes: 8 additions & 0 deletions app/error-route-test/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use client';

export default function Page() {
setTimeout(() => {
throw new Error('An Error');
}, 1000);
return <div>ERROR TESTING PAGE</div>;
}
36 changes: 36 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Analytics from '../components/head/Analytics';
import GoogleTagManagerScript from '../components/head/GoogleTagManagerScript';
import RollbarScript from '../components/head/RollbarScript';
import ErrorBoundary from '../components/layout/ErrorBoundary';
import { newRelicInit } from '../config/newRelic';
import rootMetadata from './rootMetadata';
import ThemeRegistry from './ThemeRegistry';

export const metadata = rootMetadata;

export default async function RootLayout({
// Layouts must accept a children prop.
// This will be populated with nested layouts or pages
children,
}: {
children: React.ReactNode;
}) {
const NewRelicScript = await newRelicInit();
return (
<html lang="en">
<body>
{/*
We should be using next third party library https://nextjs.org/docs/app/building-your-application/optimizing/third-party-libraries#google-tag-manager
but sending an event using sendGTMEvent requires an object rather than a list of arguments so the current gtag api function would need to be adapted
*/}
<GoogleTagManagerScript />
<RollbarScript />
<ErrorBoundary>
<ThemeRegistry>{children}</ThemeRegistry>
</ErrorBoundary>
{NewRelicScript}
<Analytics />
</body>
</html>
);
}
3 changes: 3 additions & 0 deletions app/public-route-test/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default async function Page() {
return <div>PUBLIC TESTING PAGE</div>;
}
32 changes: 32 additions & 0 deletions app/rootMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Metadata } from 'next';
import { PRIMARY_MAIN_COLOR } from '../constants/common';

const descriptionContent =
'Join us on your healing journey. Bloom is here for you to learn, heal and grow towards a confident future. It is bought to you by Chayn, a global non-profit, run by survivors and allies from around the world.';
const twitterDescriptionContent =
'Join us on your healing journey. Bloom is here for you to learn, heal and grow towards a confident future. It is bought to you by Chayn, a global non-profit, run by survivors and allies from around the world.';
const imageAltContent =
'An cartoon drawing of a person with almost shoulder length hair against a pink background. They have flowers and leaves coming out of their head. The word "Bloom" hovers above the person.';

// Nextjs automatically includes for each route two default meta tags, charset and viewport
// https://nextjs.org/docs/app/building-your-application/optimizing/metadata#default-fields
const rootMetadata: Metadata = {
title: 'Bloom',
openGraph: {
title: 'Welcome to Bloom',
description: descriptionContent,
images: [{ url: '/preview.png', alt: imageAltContent }],
},
twitter: {
description: twitterDescriptionContent,
card: 'summary_large_image',
images: [],
},
manifest: '/manifest.json',
icons: [{ rel: 'apple-touch-icon', url: '/icons/apple/icon-120x120.png' }],
other: {
'theme-color': PRIMARY_MAIN_COLOR,
},
};

export default rootMetadata;
13 changes: 13 additions & 0 deletions components/head/Analytics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Analytics as VercelAnalytics } from '@vercel/analytics/react';
import { Hotjar } from 'nextjs-hotjar';

export default function Analytics() {
return (
<>
{!!process.env.NEXT_PUBLIC_HOTJAR_ID && process.env.NEXT_PUBLIC_ENV !== 'local' && (
<Hotjar id={process.env.NEXT_PUBLIC_HOTJAR_ID} sv={6} strategy="lazyOnload" />
)}
<VercelAnalytics />
</>
);
}
2 changes: 1 addition & 1 deletion components/head/GoogleTagManagerScript.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const GoogleTagManagerScript = () => {
return (
<Script
id="gtag"
strategy="worker"
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
Expand Down
7 changes: 6 additions & 1 deletion components/head/RollbarScript.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import Script from 'next/script';

const RollbarScript = () => {
return (
<script
// eslint-disable-next-line @next/next/no-before-interactive-script-outside-document
<Script
id="rollbar"
strategy="beforeInteractive"
dangerouslySetInnerHTML={{
__html: `
var _rollbarConfig = {
Expand Down
2 changes: 2 additions & 0 deletions components/layout/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use client';

import { Alert, Snackbar } from '@mui/material';
import { Component, ErrorInfo, ReactNode } from 'react';

Expand Down
46 changes: 46 additions & 0 deletions config/newRelic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import newrelic from 'newrelic';
import Script from 'next/script';

// Configuration according to Newrelic app router example
// See https://github.com/newrelic/newrelic-node-nextjs?tab=readme-ov-file#example-projects
export const newRelicInit = async () => {
// @ts-ignore
if (newrelic.agent.collector.isConnected() === false) {
await new Promise((resolve) => {
// @ts-ignore
newrelic.agent.on('connected', resolve);
});
}

const browserTimingHeader = newrelic.getBrowserTimingHeader({
hasToRemoveScriptWrapper: true,
// @ts-ignore
allowTransactionlessInjection: true,
});

return <NewRelicScript browserTimingHeader={browserTimingHeader} />;
};

export type NewRelicScriptProps = {
browserTimingHeader: string;
};

const NewRelicScript = ({ browserTimingHeader }: NewRelicScriptProps) => {
return (
// eslint-disable-next-line @next/next/no-before-interactive-script-outside-document
<Script
// We have to set an id for inline scripts.
// See https://nextjs.org/docs/app/building-your-application/optimizing/scripts#inline-scripts
id="nr-browser-agent"
// By setting the strategy to "beforeInteractive" we guarantee that
// the script will be added to the document's `head` element.
strategy="beforeInteractive"
// The body of the script element comes from the async evaluation
// of `getInitialProps`. We use the special
// `dangerouslySetInnerHTML` to provide that element body. Since
// it requires an object with an `__html` property, we pass in an
// object literal.
dangerouslySetInnerHTML={{ __html: browserTimingHeader }}
/>
);
};
2 changes: 2 additions & 0 deletions constants/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ export type ErrorDisplay =
| ReactElement<any, string | JSXElementConstructor<any>>
| ReactNodeArray
| null;

export const PRIMARY_MAIN_COLOR = '#F3D6D8';
1 change: 1 addition & 0 deletions next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
18 changes: 18 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,26 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});

// Configuration according to Newrelic app router example
// See https://github.com/newrelic/newrelic-node-nextjs?tab=readme-ov-file#example-projects
const nrExternals = require('@newrelic/next/load-externals');

module.exports = withBundleAnalyzer(
withPWA({
experimental: {
// Without this setting, the Next.js compilation step will routinely
// try to import files such as `LICENSE` from the `newrelic` module.
// See https://nextjs.org/docs/app/api-reference/next-config-js/serverComponentsExternalPackages.
serverComponentsExternalPackages: ['newrelic'],
},

// In order for newrelic to effectively instrument a Next.js application,
// the modules that newrelic supports should not be mangled by webpack. Thus,
// we need to "externalize" all of the modules that newrelic supports.
webpack: (config) => {
nrExternals(config);
return config;
},
reactStrictMode: true,
publicRuntimeConfig: {
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@
"prepare": "husky"
},
"dependencies": {
"@emotion/cache": "^11.11.0",
"@emotion/cache": "^11.13.1",
"@emotion/react": "^11.11.4",
"@emotion/server": "^11.11.0",
"@emotion/styled": "^11.11.5",
"@mui/icons-material": "^5.16.0",
"@mui/lab": "^5.0.0-alpha.171",
"@mui/material": "^5.16.1",
"@mui/material-nextjs": "^6.0.2",
"@newrelic/next": "^0.10.0",
"@reduxjs/toolkit": "^2.2.5",
"@storyblok/react": "^3.0.0",
Expand Down
4 changes: 4 additions & 0 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import { useEffect } from 'react';
import { Provider } from 'react-redux';
import CrispScript from '../components/crisp/CrispScript';
import GoogleTagManagerScript from '../components/head/GoogleTagManagerScript';
import RollbarScript from '../components/head/RollbarScript';
import Consent from '../components/layout/Consent';
import ErrorBoundary from '../components/layout/ErrorBoundary';
import Footer from '../components/layout/Footer';
Expand Down Expand Up @@ -42,7 +44,7 @@
function MyApp(props: MyAppProps) {
const {
Component,
emotionCache = clientSideEmotionCache,

Check failure on line 47 in pages/_app.tsx

View workflow job for this annotation

GitHub Actions / build-and-test

Type 'import("/home/runner/work/***/***/node_modules/@emotion/cache/node_modules/@emotion/utils/dist/declarations/src/types").EmotionCache' is not assignable to type 'import("/home/runner/work/***/***/node_modules/@emotion/utils/types/index").EmotionCache'.
pageProps,
}: {
Component: NextComponentType<NextPageContext<any>, any, any>;
Expand Down Expand Up @@ -81,6 +83,8 @@
<title>Bloom</title>
<meta name="viewport" content="initial-scale=1, width=device-width" />
</Head>
<GoogleTagManagerScript />
<RollbarScript />
<CrispScript />
<ThemeProvider theme={theme}>
<CssBaseline />
Expand Down
4 changes: 0 additions & 4 deletions pages/_document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
import { AppType } from 'next/app';
import Document, { Head, Html, Main, NextScript } from 'next/document';
import * as React from 'react';
import GoogleTagManagerScript from '../components/head/GoogleTagManagerScript';
import OpenGraphMetadata from '../components/head/OpenGraphMetadata';
import RollbarScript from '../components/head/RollbarScript';
import createEmotionCache from '../config/emotionCache';
import { MyAppProps } from './_app';

Expand All @@ -27,8 +25,6 @@
rel="stylesheet"
/>
<OpenGraphMetadata />
<GoogleTagManagerScript />
<RollbarScript />
</Head>
<body>
<Main />
Expand Down Expand Up @@ -87,13 +83,13 @@
// You can consider sharing the same Emotion cache between all the SSR requests to speed up performance.
// However, be aware that it can have global side effects.
const cache = createEmotionCache();
const { extractCriticalToChunks } = createEmotionServer(cache);

Check failure on line 86 in pages/_document.tsx

View workflow job for this annotation

GitHub Actions / build-and-test

Argument of type 'import("/home/runner/work/***/***/node_modules/@emotion/cache/node_modules/@emotion/utils/dist/declarations/src/types").EmotionCache' is not assignable to parameter of type 'import("/home/runner/work/***/***/node_modules/@emotion/utils/types/index").EmotionCache'.

ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App: React.ComponentType<React.ComponentProps<AppType> & MyAppProps>) =>
function EnhanceApp(props) {
return <App emotionCache={cache} {...props} />;

Check failure on line 92 in pages/_document.tsx

View workflow job for this annotation

GitHub Actions / build-and-test

Type 'import("/home/runner/work/***/***/node_modules/@emotion/cache/node_modules/@emotion/utils/dist/declarations/src/types").EmotionCache' is not assignable to type 'import("/home/runner/work/***/***/node_modules/@emotion/utils/types/index").EmotionCache'.
},
});

Expand Down
5 changes: 4 additions & 1 deletion styles/theme.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
'use client';

import { createTheme, lighten, responsiveFontSizes } from '@mui/material/styles';
import { PRIMARY_MAIN_COLOR } from '../constants/common';

// If you want to declare custom colours that aren't officially in the palette, add them here
declare module '@mui/material/styles' {
Expand All @@ -16,7 +19,7 @@ declare module '@mui/material/styles' {
let theme = createTheme({
palette: {
primary: {
main: '#F3D6D8',
main: PRIMARY_MAIN_COLOR,
light: '#F7E2E4',
dark: '#EA0050',
},
Expand Down
45 changes: 45 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,13 @@
dependencies:
regenerator-runtime "^0.14.0"

"@babel/runtime@^7.25.0":
version "7.25.6"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.6.tgz#9afc3289f7184d8d7f98b099884c26317b9264d2"
integrity sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==
dependencies:
regenerator-runtime "^0.14.0"

"@babel/template@^7.24.7", "@babel/template@^7.3.3":
version "7.24.7"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315"
Expand Down Expand Up @@ -1086,6 +1093,17 @@
"@emotion/weak-memoize" "^0.3.1"
stylis "4.2.0"

"@emotion/cache@^11.13.1":
version "11.13.1"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.13.1.tgz#fecfc54d51810beebf05bf2a161271a1a91895d7"
integrity sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==
dependencies:
"@emotion/memoize" "^0.9.0"
"@emotion/sheet" "^1.4.0"
"@emotion/utils" "^1.4.0"
"@emotion/weak-memoize" "^0.4.0"
stylis "4.2.0"

"@emotion/hash@^0.9.1":
version "0.9.1"
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43"
Expand All @@ -1103,6 +1121,11 @@
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17"
integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==

"@emotion/memoize@^0.9.0":
version "0.9.0"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102"
integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==

"@emotion/react@^11.11.4":
version "11.11.4"
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.4.tgz#3a829cac25c1f00e126408fab7f891f00ecc3c1d"
Expand Down Expand Up @@ -1143,6 +1166,11 @@
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec"
integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==

"@emotion/sheet@^1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.4.0.tgz#c9299c34d248bc26e82563735f78953d2efca83c"
integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==

"@emotion/styled@^11.11.5":
version "11.11.5"
resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.11.5.tgz#0c5c8febef9d86e8a926e663b2e5488705545dfb"
Expand Down Expand Up @@ -1170,11 +1198,21 @@
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4"
integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==

"@emotion/utils@^1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.0.tgz#262f1d02aaedb2ec91c83a0955dd47822ad5fbdd"
integrity sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==

"@emotion/weak-memoize@^0.3.1":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6"
integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==

"@emotion/weak-memoize@^0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6"
integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==

"@eslint-community/eslint-utils@^4.2.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
Expand Down Expand Up @@ -2017,6 +2055,13 @@
clsx "^2.1.0"
prop-types "^15.8.1"

"@mui/material-nextjs@^6.0.2":
version "6.0.2"
resolved "https://registry.yarnpkg.com/@mui/material-nextjs/-/material-nextjs-6.0.2.tgz#db2d27963803f905f10a6810915eca9aaf354e67"
integrity sha512-P5ZZ6P2UXstuW746J9uLkwAHIB/HKnjWcn4I4kF8uFinGpIbEt8BC58BCSqlfesB/pHNxJqaSPWDB4wBBFc42g==
dependencies:
"@babel/runtime" "^7.25.0"

"@mui/material@^5.16.1":
version "5.16.1"
resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.16.1.tgz#6fcef9b5709df5864cf0b0bc0ea7b453a9d9e420"
Expand Down
Loading