diff --git a/docs/data/toolpad/core/components/app-provider/AppProviderBasic.js b/docs/data/toolpad/core/components/app-provider/AppProviderBasic.js index 914bd2bed91..35af75765dc 100644 --- a/docs/data/toolpad/core/components/app-provider/AppProviderBasic.js +++ b/docs/data/toolpad/core/components/app-provider/AppProviderBasic.js @@ -60,7 +60,7 @@ DemoPageContent.propTypes = { function AppProviderBasic(props) { const { window } = props; - const [pathname, setPathname] = React.useState('/page'); + const [pathname, setPathname] = React.useState('page'); const router = React.useMemo(() => { return { diff --git a/docs/data/toolpad/core/components/app-provider/AppProviderBasic.tsx b/docs/data/toolpad/core/components/app-provider/AppProviderBasic.tsx index 224b603857a..d64b23039e4 100644 --- a/docs/data/toolpad/core/components/app-provider/AppProviderBasic.tsx +++ b/docs/data/toolpad/core/components/app-provider/AppProviderBasic.tsx @@ -64,7 +64,7 @@ interface DemoProps { export default function AppProviderBasic(props: DemoProps) { const { window } = props; - const [pathname, setPathname] = React.useState('/page'); + const [pathname, setPathname] = React.useState('page'); const router = React.useMemo(() => { return { diff --git a/docs/data/toolpad/core/components/app-provider/AppProviderTheme.js b/docs/data/toolpad/core/components/app-provider/AppProviderTheme.js index 36b215727fe..2f6b4a86541 100644 --- a/docs/data/toolpad/core/components/app-provider/AppProviderTheme.js +++ b/docs/data/toolpad/core/components/app-provider/AppProviderTheme.js @@ -14,12 +14,12 @@ const NAVIGATION = [ title: 'Main items', }, { - slug: '/page', + segment: '/page', title: 'Page', icon: , }, { - slug: '/page-2', + segment: '/page-2', title: 'Page 2', icon: , }, @@ -30,8 +30,8 @@ const customTheme = extendTheme({ light: { palette: { background: { - default: '#E2FAFF', - paper: '#D9FAFF', + default: '#F9F9FE', + paper: '#EEEEF9', }, }, }, @@ -78,7 +78,7 @@ DemoPageContent.propTypes = { function AppProviderTheme(props) { const { window } = props; - const [pathname, setPathname] = React.useState('/page'); + const [pathname, setPathname] = React.useState('page'); const router = React.useMemo(() => { return { diff --git a/docs/data/toolpad/core/components/app-provider/AppProviderTheme.tsx b/docs/data/toolpad/core/components/app-provider/AppProviderTheme.tsx index e034fea0b92..51a6ecfda54 100644 --- a/docs/data/toolpad/core/components/app-provider/AppProviderTheme.tsx +++ b/docs/data/toolpad/core/components/app-provider/AppProviderTheme.tsx @@ -14,12 +14,12 @@ const NAVIGATION: Navigation = [ title: 'Main items', }, { - slug: '/page', + segment: '/page', title: 'Page', icon: , }, { - slug: '/page-2', + segment: '/page-2', title: 'Page 2', icon: , }, @@ -30,8 +30,8 @@ const customTheme = extendTheme({ light: { palette: { background: { - default: '#E2FAFF', - paper: '#D9FAFF', + default: '#F9F9FE', + paper: '#EEEEF9', }, }, }, @@ -82,7 +82,7 @@ interface DemoProps { export default function AppProviderTheme(props: DemoProps) { const { window } = props; - const [pathname, setPathname] = React.useState('/page'); + const [pathname, setPathname] = React.useState('page'); const router = React.useMemo(() => { return { diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.js b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.js index 05f1a3b7c0a..8b5e7dc0466 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.js +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.js @@ -92,7 +92,7 @@ DemoPageContent.propTypes = { function DashboardLayoutBasic(props) { const { window } = props; - const [pathname, setPathname] = React.useState('/page'); + const [pathname, setPathname] = React.useState('dashboard'); const router = React.useMemo(() => { return { diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.tsx b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.tsx index b68ccb538d9..fd2b310d2cc 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.tsx +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.tsx @@ -96,7 +96,7 @@ interface DemoProps { export default function DashboardLayoutBasic(props: DemoProps) { const { window } = props; - const [pathname, setPathname] = React.useState('/page'); + const [pathname, setPathname] = React.useState('dashboard'); const router = React.useMemo(() => { return { diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.js b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.js index 5e2e634f07d..605f383ea89 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.js +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.js @@ -56,7 +56,7 @@ DemoPageContent.propTypes = { function DashboardLayoutBranding(props) { const { window } = props; - const [pathname, setPathname] = React.useState('/page'); + const [pathname, setPathname] = React.useState('dashboard'); const router = React.useMemo(() => { return { diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.tsx b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.tsx index b462ef4d023..d246ee44077 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.tsx +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.tsx @@ -60,7 +60,7 @@ interface DemoProps { export default function DashboardLayoutBranding(props: DemoProps) { const { window } = props; - const [pathname, setPathname] = React.useState('/page'); + const [pathname, setPathname] = React.useState('dashboard'); const router = React.useMemo(() => { return { diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationActions.js b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationActions.js new file mode 100644 index 00000000000..eaf2dbbedea --- /dev/null +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationActions.js @@ -0,0 +1,157 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import Box from '@mui/material/Box'; +import Chip from '@mui/material/Chip'; +import IconButton from '@mui/material/IconButton'; +import Menu from '@mui/material/Menu'; +import MenuItem from '@mui/material/MenuItem'; +import Typography from '@mui/material/Typography'; +import { extendTheme } from '@mui/material/styles'; +import PersonIcon from '@mui/icons-material/Person'; +import CallIcon from '@mui/icons-material/Call'; +import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; +import CallMadeIcon from '@mui/icons-material/CallMade'; +import CallReceivedIcon from '@mui/icons-material/CallReceived'; +import { AppProvider } from '@toolpad/core/AppProvider'; +import { DashboardLayout } from '@toolpad/core/DashboardLayout'; + +const demoTheme = extendTheme({ + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, +}); + +function DemoPageContent({ pathname }) { + return ( + + Dashboard content for {pathname} + + ); +} + +DemoPageContent.propTypes = { + pathname: PropTypes.string.isRequired, +}; + +function DashboardLayoutNavigationActions(props) { + const { window } = props; + + const [pathname, setPathname] = React.useState('contacts'); + + const router = React.useMemo(() => { + return { + pathname, + searchParams: new URLSearchParams(), + navigate: (path) => setPathname(String(path)), + }; + }, [pathname]); + + const [popoverAnchorEl, setPopoverAnchorEl] = React.useState(null); + + const isPopoverOpen = Boolean(popoverAnchorEl); + const popoverId = isPopoverOpen ? 'simple-popover' : undefined; + + const handlePopoverButtonClick = (event) => { + event.stopPropagation(); + setPopoverAnchorEl(event.currentTarget); + }; + + const handlePopoverClose = (event) => { + event.stopPropagation(); + setPopoverAnchorEl(null); + }; + + // Remove this const when copying and pasting into your project. + const demoWindow = window !== undefined ? window() : undefined; + + return ( + // preview-start + , + action: , + }, + { + segment: '/calls', + title: 'Calls', + icon: , + action: ( + + + + + + New call + Mark all as read + + + ), + children: [ + { + segment: '/made', + title: 'Made', + icon: , + action: , + }, + { + segment: '/received', + title: 'Received', + icon: , + action: , + }, + ], + }, + ]} + router={router} + theme={demoTheme} + window={demoWindow} + > + + + + + // preview-end + ); +} + +DashboardLayoutNavigationActions.propTypes = { + /** + * Injected by the documentation to work in an iframe. + * Remove this when copying and pasting into your project. + */ + window: PropTypes.func, +}; + +export default DashboardLayoutNavigationActions; diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationActions.tsx b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationActions.tsx new file mode 100644 index 00000000000..e5623b8c2fc --- /dev/null +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationActions.tsx @@ -0,0 +1,151 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import Chip from '@mui/material/Chip'; +import IconButton from '@mui/material/IconButton'; +import Menu from '@mui/material/Menu'; +import MenuItem from '@mui/material/MenuItem'; +import Typography from '@mui/material/Typography'; +import { extendTheme } from '@mui/material/styles'; +import PersonIcon from '@mui/icons-material/Person'; +import CallIcon from '@mui/icons-material/Call'; +import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; +import CallMadeIcon from '@mui/icons-material/CallMade'; +import CallReceivedIcon from '@mui/icons-material/CallReceived'; +import { AppProvider, Router } from '@toolpad/core/AppProvider'; +import { DashboardLayout } from '@toolpad/core/DashboardLayout'; + +const demoTheme = extendTheme({ + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, +}); + +function DemoPageContent({ pathname }: { pathname: string }) { + return ( + + Dashboard content for {pathname} + + ); +} + +interface DemoProps { + /** + * Injected by the documentation to work in an iframe. + * Remove this when copying and pasting into your project. + */ + window?: () => Window; +} + +export default function DashboardLayoutNavigationActions(props: DemoProps) { + const { window } = props; + + const [pathname, setPathname] = React.useState('contacts'); + + const router = React.useMemo(() => { + return { + pathname, + searchParams: new URLSearchParams(), + navigate: (path) => setPathname(String(path)), + }; + }, [pathname]); + + const [popoverAnchorEl, setPopoverAnchorEl] = + React.useState(null); + + const isPopoverOpen = Boolean(popoverAnchorEl); + const popoverId = isPopoverOpen ? 'simple-popover' : undefined; + + const handlePopoverButtonClick = (event: React.MouseEvent) => { + event.stopPropagation(); + setPopoverAnchorEl(event.currentTarget); + }; + + const handlePopoverClose = (event: React.MouseEvent) => { + event.stopPropagation(); + setPopoverAnchorEl(null); + }; + + // Remove this const when copying and pasting into your project. + const demoWindow = window !== undefined ? window() : undefined; + + return ( + // preview-start + , + action: , + }, + { + segment: '/calls', + title: 'Calls', + icon: , + action: ( + + + + + + New call + Mark all as read + + + ), + children: [ + { + segment: '/made', + title: 'Made', + icon: , + action: , + }, + { + segment: '/received', + title: 'Received', + icon: , + action: , + }, + ], + }, + ]} + router={router} + theme={demoTheme} + window={demoWindow} + > + + + + + // preview-end + ); +} diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationActions.tsx.preview b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationActions.tsx.preview new file mode 100644 index 00000000000..6d82cfe85d1 --- /dev/null +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationActions.tsx.preview @@ -0,0 +1,62 @@ +, + action: , + }, + { + segment: '/calls', + title: 'Calls', + icon: , + action: ( + + + + + + New call + Mark all as read + + + ), + children: [ + { + segment: '/made', + title: 'Made', + icon: , + action: , + }, + { + segment: '/received', + title: 'Received', + icon: , + action: , + }, + ], + }, + ]} + router={router} + theme={demoTheme} + window={demoWindow} +> + + + + \ No newline at end of file diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.js b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationItems.js similarity index 96% rename from docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.js rename to docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationItems.js index 2bb4f6ccf3c..8ca6ba156a7 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.js +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationItems.js @@ -40,10 +40,10 @@ DemoPageContent.propTypes = { pathname: PropTypes.string.isRequired, }; -function DashboardLayoutNavigation(props) { +function DashboardLayoutNavigationItems(props) { const { window } = props; - const [pathname, setPathname] = React.useState('/page'); + const [pathname, setPathname] = React.useState('home'); const router = React.useMemo(() => { return { @@ -211,7 +211,7 @@ function DashboardLayoutNavigation(props) { ); } -DashboardLayoutNavigation.propTypes = { +DashboardLayoutNavigationItems.propTypes = { /** * Injected by the documentation to work in an iframe. * Remove this when copying and pasting into your project. @@ -219,4 +219,4 @@ DashboardLayoutNavigation.propTypes = { window: PropTypes.func, }; -export default DashboardLayoutNavigation; +export default DashboardLayoutNavigationItems; diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.tsx b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationItems.tsx similarity index 97% rename from docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.tsx rename to docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationItems.tsx index 9fc7f8493b3..7597bb58ef0 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.tsx +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationItems.tsx @@ -43,10 +43,10 @@ interface DemoProps { window?: () => Window; } -export default function DashboardLayoutNavigation(props: DemoProps) { +export default function DashboardLayoutNavigationItems(props: DemoProps) { const { window } = props; - const [pathname, setPathname] = React.useState('/page'); + const [pathname, setPathname] = React.useState('home'); const router = React.useMemo(() => { return { diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.tsx.preview b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationItems.tsx.preview similarity index 100% rename from docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.tsx.preview rename to docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigationItems.tsx.preview diff --git a/docs/data/toolpad/core/components/dashboard-layout/dashboard-layout.md b/docs/data/toolpad/core/components/dashboard-layout/dashboard-layout.md index 57481961674..44f31f12474 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/dashboard-layout.md +++ b/docs/data/toolpad/core/components/dashboard-layout/dashboard-layout.md @@ -30,13 +30,23 @@ This can be done via the `branding` prop in the [AppProvider](https://mui.com/to ## Navigation -The `navigation` prop in the [AppProvider](https://mui.com/toolpad/core/react-app-provider/) allows for setting any type of navigation structure in the `DashboardLayout` sidebar by including different navigation elements as building blocks in any order, such as: - -- links `{ slug: '/home', title: 'Home', icon: }`; -- headings `{ kind: 'header', title: 'Epic Fantasy' }`; -- dividers `{ kind: 'divider' }`; -- collapsible nested navigation `{ title: 'Fantasy', icon: , children: [ ... ] }`. +The `navigation` prop in the [AppProvider](https://mui.com/toolpad/core/react-app-provider/) allows for setting any type of navigation structure in the `DashboardLayout` sidebar by including different navigation elements as building blocks in any order. The flexibility in composing and ordering these different elements allows for a great variety of navigation structures to fit your use case. -{{"demo": "DashboardLayoutNavigation.js", "height": 640, "iframe": true}} +### Navigation Items + +The main navigation items that can be used are: + +- **Links:** `{ segment: '/home', title: 'Home', icon: }`; +- **Headings:** `{ kind: 'header', title: 'Epic Fantasy' }`; +- **Dividers:** `{ kind: 'divider' }`; +- **Collapsible nested navigation:** `{ title: 'Fantasy', icon: , children: [ ... ] }`. + +{{"demo": "DashboardLayoutNavigationItems.js", "height": 640, "iframe": true}} + +### Navigation Actions + +Navigation links have an optional `action` prop that can be used to render any content on the right-side of the respective list item, such as badges with numbers, or buttons to toggle a popover menu. + +{{"demo": "DashboardLayoutNavigationActions.js", "height": 500, "iframe": true}} diff --git a/docs/data/toolpad/core/introduction/TutorialPages.js b/docs/data/toolpad/core/introduction/TutorialPages.js index 4d55806f518..c9d06a98633 100644 --- a/docs/data/toolpad/core/introduction/TutorialPages.js +++ b/docs/data/toolpad/core/introduction/TutorialPages.js @@ -64,7 +64,7 @@ function TutorialPages(props) { // Remove this const when copying and pasting into your project. const demoWindow = window !== undefined ? window() : undefined; - const [pathname, setPathname] = React.useState('/page'); + const [pathname, setPathname] = React.useState('page'); const router = React.useMemo(() => { return { diff --git a/docs/data/toolpad/core/introduction/TutorialPages.tsx b/docs/data/toolpad/core/introduction/TutorialPages.tsx index c72da2bbbe9..2961b113d13 100644 --- a/docs/data/toolpad/core/introduction/TutorialPages.tsx +++ b/docs/data/toolpad/core/introduction/TutorialPages.tsx @@ -67,7 +67,7 @@ export default function TutorialPages(props: DemoProps) { // Remove this const when copying and pasting into your project. const demoWindow = window !== undefined ? window() : undefined; - const [pathname, setPathname] = React.useState('/page'); + const [pathname, setPathname] = React.useState('page'); const router = React.useMemo(() => { return { diff --git a/docs/data/toolpad/core/introduction/overview.md b/docs/data/toolpad/core/introduction/overview.md index 0d36e60e06a..a2530965468 100644 --- a/docs/data/toolpad/core/introduction/overview.md +++ b/docs/data/toolpad/core/introduction/overview.md @@ -8,7 +8,7 @@ title: Toolpad Overview This framework leverages the existing suite of components offered by MUI, and ties them together with the most commonly-used backend integrations to help you create dashboards fast. Imagine a React dashboard template but with backend features like authentication, role-based access control and data fetching already included. It comes with the guarantee of MUI's enterprise-tested components, and the Toolpad team's focus on using the latest stable libraries, and prioritising razor-sharp performance. -{{"demo": "../components/dashboard-layout/DashboardLayoutNavigation.js", "height": 640, "iframe": true}} +{{"demo": "../components/dashboard-layout/DashboardLayoutNavigationItems.js", "height": 640, "iframe": true}} ## Overview diff --git a/docs/pages/toolpad/core/api/app-provider.json b/docs/pages/toolpad/core/api/app-provider.json index 0fef7f00c34..595160c0bc3 100644 --- a/docs/pages/toolpad/core/api/app-provider.json +++ b/docs/pages/toolpad/core/api/app-provider.json @@ -8,7 +8,7 @@ "navigation": { "type": { "name": "arrayOf", - "description": "Array<{ children?: Array<object
| { kind: 'header', title: string }
| { kind: 'divider' }>, icon?: node, kind?: 'page', segment: string, title?: string }
| { kind: 'header', title: string }
| { kind: 'divider' }>" + "description": "Array<{ action?: node, children?: Array<object
| { kind: 'header', title: string }
| { kind: 'divider' }>, icon?: node, kind?: 'page', segment: string, title?: string }
| { kind: 'header', title: string }
| { kind: 'divider' }>" }, "default": "[]" }, diff --git a/examples/core-tutorial/app/layout.tsx b/examples/core-tutorial/app/layout.tsx index 20373eade60..b1849cd8ebc 100644 --- a/examples/core-tutorial/app/layout.tsx +++ b/examples/core-tutorial/app/layout.tsx @@ -9,7 +9,7 @@ const NAVIGATION: Navigation = [ title: 'Main items', }, { - slug: '/page', + segment: '/page', title: 'Page', icon: , }, diff --git a/packages/toolpad-core/package.json b/packages/toolpad-core/package.json index aaf8e6ae73c..68937fa51be 100644 --- a/packages/toolpad-core/package.json +++ b/packages/toolpad-core/package.json @@ -75,8 +75,8 @@ "vitest": "beta" }, "peerDependencies": { - "@mui/icons-material": "v6.0.0-beta.2", - "@mui/material": "v6.0.0-beta.2", + "@mui/icons-material": "6.0.0-beta.2", + "@mui/material": "6.0.0-beta.2", "next": "^14", "react": "^18" }, diff --git a/packages/toolpad-core/src/AppProvider/AppProvider.tsx b/packages/toolpad-core/src/AppProvider/AppProvider.tsx index 9a72fab844d..d901d41e9ae 100644 --- a/packages/toolpad-core/src/AppProvider/AppProvider.tsx +++ b/packages/toolpad-core/src/AppProvider/AppProvider.tsx @@ -39,6 +39,7 @@ export interface NavigationPageItem { segment: string; title?: string; icon?: React.ReactNode; + action?: React.ReactNode; children?: Navigation; } @@ -152,6 +153,7 @@ AppProvider.propTypes /* remove-proptypes */ = { navigation: PropTypes.arrayOf( PropTypes.oneOfType([ PropTypes.shape({ + action: PropTypes.node, children: PropTypes.arrayOf( PropTypes.oneOfType([ PropTypes.object, diff --git a/packages/toolpad-core/src/DashboardLayout/DashboardLayout.test.tsx b/packages/toolpad-core/src/DashboardLayout/DashboardLayout.test.tsx index 173e1839293..c6a4818dc7c 100644 --- a/packages/toolpad-core/src/DashboardLayout/DashboardLayout.test.tsx +++ b/packages/toolpad-core/src/DashboardLayout/DashboardLayout.test.tsx @@ -42,6 +42,7 @@ describe('DashboardLayout', () => { test('can switch theme', async () => { const user = userEvent.setup(); + render( Hello world @@ -116,6 +117,7 @@ describe('DashboardLayout', () => { ]; const user = userEvent.setup(); + render( Hello world @@ -151,4 +153,32 @@ describe('DashboardLayout', () => { expect(within(navigation).getByText('Sales')).toBeTruthy(); expect(within(navigation).getByText('Traffic')).toBeTruthy(); }); + + test('renders navigation actions', async () => { + const NAVIGATION: Navigation = [ + { + title: 'Item 1', + segment: '/item1', + icon: , + action:
Action 1
, + }, + { + title: 'Item', + segment: '/item 2', + icon: , + action:
Action 2
, + }, + ]; + + render( + + Hello world + , + ); + + const navigation = screen.getByRole('navigation'); + + expect(within(navigation).getByText('Action 1')).toBeTruthy(); + expect(within(navigation).getByText('Action 2')).toBeTruthy(); + }); }); diff --git a/packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx b/packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx index ffe4f654d3e..dfdfb23c422 100644 --- a/packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx +++ b/packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx @@ -270,6 +270,7 @@ function DashboardSidebarSubNavigation({ }, }} /> + {navigationItem.action ?? null} {navigationItem.children ? nestedNavigationCollapseIcon : null} diff --git a/packages/toolpad-core/src/nextjs/AppProvider.test.tsx b/packages/toolpad-core/src/nextjs/AppProvider.test.tsx index 321038792b2..bf271cbeceb 100644 --- a/packages/toolpad-core/src/nextjs/AppProvider.test.tsx +++ b/packages/toolpad-core/src/nextjs/AppProvider.test.tsx @@ -29,7 +29,7 @@ interface RouterTestProps { } function RouterTest({ children }: RouterTestProps) { - const [pathname, setPathname] = React.useState('/page'); + const [pathname, setPathname] = React.useState('page'); const router = React.useMemo(() => { return { diff --git a/playground/nextjs-pages/src/pages/_app.tsx b/playground/nextjs-pages/src/pages/_app.tsx index 0d961ed4f33..4ddb2213303 100644 --- a/playground/nextjs-pages/src/pages/_app.tsx +++ b/playground/nextjs-pages/src/pages/_app.tsx @@ -23,12 +23,12 @@ const NAVIGATION: Navigation = [ title: 'Main items', }, { - slug: '/', + segment: '/', title: 'Dashboard', icon: , }, { - slug: '/orders', + segment: '/orders', title: 'Orders', icon: , }, diff --git a/playground/nextjs/src/app/layout.tsx b/playground/nextjs/src/app/layout.tsx index 4d23da71221..ae8f04dacd0 100644 --- a/playground/nextjs/src/app/layout.tsx +++ b/playground/nextjs/src/app/layout.tsx @@ -11,12 +11,12 @@ const NAVIGATION: Navigation = [ title: 'Main items', }, { - slug: '', + segment: '', title: 'Dashboard', icon: , }, { - slug: 'orders', + segment: 'orders', title: 'Orders', icon: , },