From 8c5698cd0a18c4f40a8b907a95b2bb3b4ddedab7 Mon Sep 17 00:00:00 2001 From: Bharat Kashyap Date: Wed, 19 Mar 2025 17:09:24 +0530 Subject: [PATCH 1/6] fix: Add CRUD to themed example --- .../employees/[[...segments]]/page.tsx | 84 +++++++ .../app/(dashboard)/layout.tsx | 21 +- .../app/components/CustomDataGrid.tsx | 19 +- .../auth-nextjs-themed/app/mocks/employees.ts | 225 ++++++++++++++++++ examples/core/auth-nextjs-themed/package.json | 5 +- .../theme/customizations/dataDisplay.tsx | 16 ++ 6 files changed, 364 insertions(+), 6 deletions(-) create mode 100644 examples/core/auth-nextjs-themed/app/(dashboard)/employees/[[...segments]]/page.tsx create mode 100644 examples/core/auth-nextjs-themed/app/mocks/employees.ts diff --git a/examples/core/auth-nextjs-themed/app/(dashboard)/employees/[[...segments]]/page.tsx b/examples/core/auth-nextjs-themed/app/(dashboard)/employees/[[...segments]]/page.tsx new file mode 100644 index 00000000000..c2f2115195d --- /dev/null +++ b/examples/core/auth-nextjs-themed/app/(dashboard)/employees/[[...segments]]/page.tsx @@ -0,0 +1,84 @@ +'use client'; +import * as React from 'react'; +import { usePathname, useRouter } from 'next/navigation'; +import { CrudProvider, List, Create, Edit, Show } from '@toolpad/core/Crud'; +import { employeesDataSource, Employee, employeesCache } from '../../../mocks/employees'; +import CustomDataGrid from '../../../components/CustomDataGrid'; + +function matchPath(pattern: string, pathname: string): string | null { + const regex = new RegExp(`^${pattern.replace(/:[^/]+/g, '([^/]+)')}$`); + const match = pathname.match(regex); + return match ? match[1] : null; +} + +export default function EmployeesCrudPage() { + const pathname = usePathname(); + const router = useRouter(); + + const rootPath = '/employees'; + const listPath = rootPath; + const showPath = `${rootPath}/:employeeId`; + const createPath = `${rootPath}/new`; + const editPath = `${rootPath}/:employeeId/edit`; + + const showEmployeeId = matchPath(showPath, pathname); + const editEmployeeId = matchPath(editPath, pathname); + + const handleRowClick = React.useCallback( + (employeeId: string | number) => { + console.log('Clicked on row with ID', employeeId); + router.push(`${rootPath}/${String(employeeId)}`); + }, + [router], + ); + + const handleCreateClick = React.useCallback(() => { + router.push(createPath); + }, [createPath, router]); + + const handleEditClick = React.useCallback( + (employeeId: string | number) => { + router.push(`${rootPath}/${String(employeeId)}/edit`); + }, + [router], + ); + + const handleCreate = React.useCallback(() => { + router.push(listPath); + }, [listPath, router]); + + const handleEdit = React.useCallback(() => { + router.push(listPath); + }, [listPath, router]); + + const handleDelete = React.useCallback(() => { + router.push(listPath); + }, [listPath, router]); + + return ( + dataSource={employeesDataSource} dataSourceCache={employeesCache}> + {pathname === listPath ? ( + + initialPageSize={25} + onRowClick={handleRowClick} + onCreateClick={handleCreateClick} + onEditClick={handleEditClick} + slots={{ + dataGrid: CustomDataGrid, + }} + /> + ) : null} + {pathname === createPath ? ( + + initialValues={{ title: 'New Employee' }} + onSubmitSuccess={handleCreate} + resetOnSubmit={false} + /> + ) : null} + {pathname !== createPath && showEmployeeId ? ( + id={showEmployeeId} onEditClick={handleEditClick} onDelete={handleDelete} /> + ) : null} + {editEmployeeId ? id={editEmployeeId} onSubmitSuccess={handleEdit} /> : null} + + ); +} diff --git a/examples/core/auth-nextjs-themed/app/(dashboard)/layout.tsx b/examples/core/auth-nextjs-themed/app/(dashboard)/layout.tsx index c12af668eb4..2bce076a6e8 100644 --- a/examples/core/auth-nextjs-themed/app/(dashboard)/layout.tsx +++ b/examples/core/auth-nextjs-themed/app/(dashboard)/layout.tsx @@ -1,10 +1,29 @@ +'use client'; import * as React from 'react'; import { DashboardLayout } from '@toolpad/core/DashboardLayout'; +import { usePathname, useParams } from 'next/navigation'; import { PageContainer } from '@toolpad/core/PageContainer'; import Copyright from '../components/Copyright'; import SidebarFooterAccount, { ToolbarAccountOverride } from './SidebarFooterAccount'; export default function Layout(props: { children: React.ReactNode }) { + const pathname = usePathname(); + const params = useParams(); + const [employeeId] = params.segments ?? []; + + const title = React.useMemo(() => { + if (pathname === '/employees/new') { + return 'New Employee'; + } + if (employeeId && pathname.includes('/edit')) { + return `Employee ${employeeId} - Edit`; + } + if (employeeId) { + return `Employee ${employeeId}`; + } + return undefined; + }, [employeeId, pathname]); + return ( - + {props.children} diff --git a/examples/core/auth-nextjs-themed/app/components/CustomDataGrid.tsx b/examples/core/auth-nextjs-themed/app/components/CustomDataGrid.tsx index 27a6050d060..909631cff7f 100644 --- a/examples/core/auth-nextjs-themed/app/components/CustomDataGrid.tsx +++ b/examples/core/auth-nextjs-themed/app/components/CustomDataGrid.tsx @@ -1,14 +1,21 @@ import * as React from 'react'; import { DataGrid } from '@mui/x-data-grid'; -import { columns, rows } from '../mocks/gridOrdersData'; -export default function CustomizedDataGrid() { +export default function CustomizedDataGrid({ + rows, + columns, + ...rest +}: { + rows?: any; + columns?: any; +}) { return (
(params.indexRelativeToCurrentPage % 2 === 0 ? 'even' : 'odd')} initialState={{ pagination: { paginationModel: { pageSize: 20 } }, @@ -26,6 +33,12 @@ export default function CustomizedDataGrid() { density="compact" slotProps={{ filterPanel: { + sx: { + '& .MuiDataGrid-filterForm': { + columnGap: 1.5, + marginTop: 2, + }, + }, filterFormProps: { logicOperatorInputProps: { variant: 'outlined', diff --git a/examples/core/auth-nextjs-themed/app/mocks/employees.ts b/examples/core/auth-nextjs-themed/app/mocks/employees.ts new file mode 100644 index 00000000000..c8b1bef889e --- /dev/null +++ b/examples/core/auth-nextjs-themed/app/mocks/employees.ts @@ -0,0 +1,225 @@ +"use client"; +import { DataModel, DataSource, DataSourceCache } from "@toolpad/core/Crud"; +import { z } from "zod"; + +type EmployeeRole = "Market" | "Finance" | "Development"; + +export interface Employee extends DataModel { + id: number; + name: string; + age: number; + joinDate: string; + role: EmployeeRole; +} + +const INITIAL_EMPLOYEES_STORE: Employee[] = [ + { + id: 1, + name: "Edward Perry", + age: 25, + joinDate: new Date().toISOString(), + role: "Finance", + }, + { + id: 2, + name: "Josephine Drake", + age: 36, + joinDate: new Date().toISOString(), + role: "Market", + }, + { + id: 3, + name: "Cody Phillips", + age: 19, + joinDate: new Date().toISOString(), + role: "Development", + }, +]; + +const getEmployeesStore = (): Employee[] => { + const value = localStorage.getItem("employees-store"); + return value ? JSON.parse(value) : INITIAL_EMPLOYEES_STORE; +}; + +const setEmployeesStore = (value: Employee[]) => { + return localStorage.setItem("employees-store", JSON.stringify(value)); +}; + +export const employeesDataSource: DataSource = { + fields: [ + { field: "id", headerName: "ID" }, + { field: "name", headerName: "Name", width: 140 }, + { field: "age", headerName: "Age", type: "number" }, + { + field: "joinDate", + headerName: "Join date", + type: "date", + valueGetter: (value: string) => value && new Date(value), + width: 140, + }, + { + field: "role", + headerName: "Department", + type: "singleSelect", + valueOptions: ["Market", "Finance", "Development"], + width: 160, + }, + ], + getMany: async ({ paginationModel, filterModel, sortModel }) => { + // Simulate loading delay + await new Promise((resolve) => { + setTimeout(resolve, 750); + }); + + const employeesStore = getEmployeesStore(); + + let filteredEmployees = [...employeesStore]; + + // Apply filters (example only) + if (filterModel?.items?.length) { + filterModel.items.forEach(({ field, value, operator }) => { + if (!field || value == null) { + return; + } + + filteredEmployees = filteredEmployees.filter((employee) => { + const employeeValue = employee[field]; + + switch (operator) { + case "contains": + return String(employeeValue) + .toLowerCase() + .includes(String(value).toLowerCase()); + case "equals": + return employeeValue === value; + case "startsWith": + return String(employeeValue) + .toLowerCase() + .startsWith(String(value).toLowerCase()); + case "endsWith": + return String(employeeValue) + .toLowerCase() + .endsWith(String(value).toLowerCase()); + case ">": + return (employeeValue as number) > value; + case "<": + return (employeeValue as number) < value; + default: + return true; + } + }); + }); + } + + // Apply sorting + if (sortModel?.length) { + filteredEmployees.sort((a, b) => { + for (const { field, sort } of sortModel) { + if ((a[field] as number) < (b[field] as number)) { + return sort === "asc" ? -1 : 1; + } + if ((a[field] as number) > (b[field] as number)) { + return sort === "asc" ? 1 : -1; + } + } + return 0; + }); + } + + // Apply pagination + const start = paginationModel.page * paginationModel.pageSize; + const end = start + paginationModel.pageSize; + const paginatedEmployees = filteredEmployees.slice(start, end); + + return { + items: paginatedEmployees, + itemCount: filteredEmployees.length, + }; + }, + getOne: async (employeeId) => { + // Simulate loading delay + await new Promise((resolve) => { + setTimeout(resolve, 750); + }); + + const employeesStore = getEmployeesStore(); + + const employeeToShow = employeesStore.find( + (employee) => employee.id === Number(employeeId) + ); + + if (!employeeToShow) { + throw new Error("Employee not found"); + } + return employeeToShow; + }, + createOne: async (data) => { + // Simulate loading delay + await new Promise((resolve) => { + setTimeout(resolve, 750); + }); + + const employeesStore = getEmployeesStore(); + + const newEmployee = { id: employeesStore.length + 1, ...data } as Employee; + + setEmployeesStore([...employeesStore, newEmployee]); + + return newEmployee; + }, + updateOne: async (employeeId, data) => { + // Simulate loading delay + await new Promise((resolve) => { + setTimeout(resolve, 750); + }); + + const employeesStore = getEmployeesStore(); + + let updatedEmployee: Employee | null = null; + + setEmployeesStore( + employeesStore.map((employee) => { + if (employee.id === Number(employeeId)) { + updatedEmployee = { ...employee, ...data }; + return updatedEmployee; + } + return employee; + }) + ); + + if (!updatedEmployee) { + throw new Error("Employee not found"); + } + return updatedEmployee; + }, + deleteOne: async (employeeId) => { + // Simulate loading delay + await new Promise((resolve) => { + setTimeout(resolve, 750); + }); + + const employeesStore = getEmployeesStore(); + + setEmployeesStore( + employeesStore.filter((employee) => employee.id !== Number(employeeId)) + ); + }, + validate: z.object({ + name: z + .string({ required_error: "Name is required" }) + .nonempty("Name is required"), + age: z + .number({ required_error: "Age is required" }) + .min(18, "Age must be at least 18"), + joinDate: z + .string({ required_error: "Join date is required" }) + .nonempty("Join date is required"), + role: z.enum(["Market", "Finance", "Development"], { + errorMap: () => ({ + message: 'Role must be "Market", "Finance" or "Development"', + }), + }), + })["~standard"].validate, +}; + +export const employeesCache = new DataSourceCache(); diff --git a/examples/core/auth-nextjs-themed/package.json b/examples/core/auth-nextjs-themed/package.json index 726f21c1421..b066c622d5b 100644 --- a/examples/core/auth-nextjs-themed/package.json +++ b/examples/core/auth-nextjs-themed/package.json @@ -20,11 +20,12 @@ "dayjs": "^1", "clsx": "^2", "@react-spring/web": "^9", - "@toolpad/core": "^0.12.0", + "@toolpad/core": "^0.13.0", "next": "^15", "next-auth": "^5.0.0-beta.25", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "zod": "^3.24.2" }, "devDependencies": { "@types/node": "^20.17.24", diff --git a/examples/core/auth-nextjs-themed/theme/customizations/dataDisplay.tsx b/examples/core/auth-nextjs-themed/theme/customizations/dataDisplay.tsx index 55580c72774..c957146d99c 100644 --- a/examples/core/auth-nextjs-themed/theme/customizations/dataDisplay.tsx +++ b/examples/core/auth-nextjs-themed/theme/customizations/dataDisplay.tsx @@ -75,6 +75,22 @@ export const dataDisplayCustomizations: Components = { }, }, }, + MuiPaper: { + styleOverrides: { + root: ({ theme }) => ({ + backgroundImage: 'none', + backgroundColor: theme.palette.background.paper, + border: '1px solid', + borderColor: theme.palette.divider, + ...theme.applyStyles('dark', { + backgroundImage: 'none', + backgroundColor: theme.palette.background.paper, + borderColor: theme.palette.divider, + }), + boxShadow: 'none', + }), + }, + }, MuiChip: { defaultProps: { size: 'small', From 7601a8310c815dd5ccc5e6bb6676346dcc35cd42 Mon Sep 17 00:00:00 2001 From: Bharat Kashyap Date: Thu, 20 Mar 2025 13:57:44 +0530 Subject: [PATCH 2/6] fix: Pedro feedback --- .../app/components/CustomDataGrid.tsx | 1 - examples/core/auth-nextjs-themed/app/layout.tsx | 7 +++++++ .../theme/customizations/dataDisplay.tsx | 13 +++++++++++++ .../theme/customizations/inputs.tsx | 3 ++- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/examples/core/auth-nextjs-themed/app/components/CustomDataGrid.tsx b/examples/core/auth-nextjs-themed/app/components/CustomDataGrid.tsx index 909631cff7f..b6339e2455c 100644 --- a/examples/core/auth-nextjs-themed/app/components/CustomDataGrid.tsx +++ b/examples/core/auth-nextjs-themed/app/components/CustomDataGrid.tsx @@ -30,7 +30,6 @@ export default function CustomizedDataGrid({ })} pageSizeOptions={[10, 20, 50]} disableColumnResize - density="compact" slotProps={{ filterPanel: { sx: { diff --git a/examples/core/auth-nextjs-themed/app/layout.tsx b/examples/core/auth-nextjs-themed/app/layout.tsx index 3fceadb73cb..530ee6800b3 100644 --- a/examples/core/auth-nextjs-themed/app/layout.tsx +++ b/examples/core/auth-nextjs-themed/app/layout.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { NextAppProvider } from '@toolpad/core/nextjs'; +import PersonIcon from '@mui/icons-material/Person'; import DashboardIcon from '@mui/icons-material/Dashboard'; import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'; import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter'; @@ -22,6 +23,12 @@ const NAVIGATION: Navigation = [ title: 'Orders', icon: , }, + { + segment: 'employees', + title: 'Employees', + icon: , + pattern: 'employees{/:employeeId}*', + }, ]; const AUTHENTICATION = { diff --git a/examples/core/auth-nextjs-themed/theme/customizations/dataDisplay.tsx b/examples/core/auth-nextjs-themed/theme/customizations/dataDisplay.tsx index c957146d99c..05d3bc831ed 100644 --- a/examples/core/auth-nextjs-themed/theme/customizations/dataDisplay.tsx +++ b/examples/core/auth-nextjs-themed/theme/customizations/dataDisplay.tsx @@ -235,4 +235,17 @@ export const dataDisplayCustomizations: Components = { }, }, }, + // @ts-expect-error + MuiDataGrid: { + styleOverrides: { + root: () => ({ + // ... existing code ... + '&.MuiDataGrid-root--densityCompact .MuiDataGrid-actionsCell button': { + width: '28px', + height: '28px', + padding: '2px', + }, + }), + }, + }, }; diff --git a/examples/core/auth-nextjs-themed/theme/customizations/inputs.tsx b/examples/core/auth-nextjs-themed/theme/customizations/inputs.tsx index 80904cfc722..fb6a5712274 100644 --- a/examples/core/auth-nextjs-themed/theme/customizations/inputs.tsx +++ b/examples/core/auth-nextjs-themed/theme/customizations/inputs.tsx @@ -370,6 +370,7 @@ export const inputsCustomizations: Components = { styleOverrides: { root: { border: 'none', + marginTop: 8, }, input: { '&::placeholder': { @@ -451,7 +452,7 @@ export const inputsCustomizations: Components = { styleOverrides: { root: ({ theme }) => ({ typography: theme.typography.caption, - marginBottom: 8, + marginTop: 8, }), }, }, From 50391d4d6cfade25dc27738354e3df2d58e5c068 Mon Sep 17 00:00:00 2001 From: Bharat Kashyap Date: Thu, 20 Mar 2025 13:58:13 +0530 Subject: [PATCH 3/6] fix: CI --- .../auth-nextjs-themed/app/mocks/employees.ts | 102 ++++++++---------- 1 file changed, 44 insertions(+), 58 deletions(-) diff --git a/examples/core/auth-nextjs-themed/app/mocks/employees.ts b/examples/core/auth-nextjs-themed/app/mocks/employees.ts index c8b1bef889e..67dfd979369 100644 --- a/examples/core/auth-nextjs-themed/app/mocks/employees.ts +++ b/examples/core/auth-nextjs-themed/app/mocks/employees.ts @@ -1,8 +1,8 @@ -"use client"; -import { DataModel, DataSource, DataSourceCache } from "@toolpad/core/Crud"; -import { z } from "zod"; +'use client'; +import { DataModel, DataSource, DataSourceCache } from '@toolpad/core/Crud'; +import { z } from 'zod'; -type EmployeeRole = "Market" | "Finance" | "Development"; +type EmployeeRole = 'Market' | 'Finance' | 'Development'; export interface Employee extends DataModel { id: number; @@ -15,53 +15,53 @@ export interface Employee extends DataModel { const INITIAL_EMPLOYEES_STORE: Employee[] = [ { id: 1, - name: "Edward Perry", + name: 'Edward Perry', age: 25, joinDate: new Date().toISOString(), - role: "Finance", + role: 'Finance', }, { id: 2, - name: "Josephine Drake", + name: 'Josephine Drake', age: 36, joinDate: new Date().toISOString(), - role: "Market", + role: 'Market', }, { id: 3, - name: "Cody Phillips", + name: 'Cody Phillips', age: 19, joinDate: new Date().toISOString(), - role: "Development", + role: 'Development', }, ]; const getEmployeesStore = (): Employee[] => { - const value = localStorage.getItem("employees-store"); + const value = localStorage.getItem('employees-store'); return value ? JSON.parse(value) : INITIAL_EMPLOYEES_STORE; }; const setEmployeesStore = (value: Employee[]) => { - return localStorage.setItem("employees-store", JSON.stringify(value)); + return localStorage.setItem('employees-store', JSON.stringify(value)); }; export const employeesDataSource: DataSource = { fields: [ - { field: "id", headerName: "ID" }, - { field: "name", headerName: "Name", width: 140 }, - { field: "age", headerName: "Age", type: "number" }, + { field: 'id', headerName: 'ID' }, + { field: 'name', headerName: 'Name', width: 140 }, + { field: 'age', headerName: 'Age', type: 'number' }, { - field: "joinDate", - headerName: "Join date", - type: "date", + field: 'joinDate', + headerName: 'Join date', + type: 'date', valueGetter: (value: string) => value && new Date(value), width: 140, }, { - field: "role", - headerName: "Department", - type: "singleSelect", - valueOptions: ["Market", "Finance", "Development"], + field: 'role', + headerName: 'Department', + type: 'singleSelect', + valueOptions: ['Market', 'Finance', 'Development'], width: 160, }, ], @@ -86,23 +86,17 @@ export const employeesDataSource: DataSource = { const employeeValue = employee[field]; switch (operator) { - case "contains": - return String(employeeValue) - .toLowerCase() - .includes(String(value).toLowerCase()); - case "equals": + case 'contains': + return String(employeeValue).toLowerCase().includes(String(value).toLowerCase()); + case 'equals': return employeeValue === value; - case "startsWith": - return String(employeeValue) - .toLowerCase() - .startsWith(String(value).toLowerCase()); - case "endsWith": - return String(employeeValue) - .toLowerCase() - .endsWith(String(value).toLowerCase()); - case ">": + case 'startsWith': + return String(employeeValue).toLowerCase().startsWith(String(value).toLowerCase()); + case 'endsWith': + return String(employeeValue).toLowerCase().endsWith(String(value).toLowerCase()); + case '>': return (employeeValue as number) > value; - case "<": + case '<': return (employeeValue as number) < value; default: return true; @@ -116,10 +110,10 @@ export const employeesDataSource: DataSource = { filteredEmployees.sort((a, b) => { for (const { field, sort } of sortModel) { if ((a[field] as number) < (b[field] as number)) { - return sort === "asc" ? -1 : 1; + return sort === 'asc' ? -1 : 1; } if ((a[field] as number) > (b[field] as number)) { - return sort === "asc" ? 1 : -1; + return sort === 'asc' ? 1 : -1; } } return 0; @@ -144,12 +138,10 @@ export const employeesDataSource: DataSource = { const employeesStore = getEmployeesStore(); - const employeeToShow = employeesStore.find( - (employee) => employee.id === Number(employeeId) - ); + const employeeToShow = employeesStore.find((employee) => employee.id === Number(employeeId)); if (!employeeToShow) { - throw new Error("Employee not found"); + throw new Error('Employee not found'); } return employeeToShow; }, @@ -184,11 +176,11 @@ export const employeesDataSource: DataSource = { return updatedEmployee; } return employee; - }) + }), ); if (!updatedEmployee) { - throw new Error("Employee not found"); + throw new Error('Employee not found'); } return updatedEmployee; }, @@ -200,26 +192,20 @@ export const employeesDataSource: DataSource = { const employeesStore = getEmployeesStore(); - setEmployeesStore( - employeesStore.filter((employee) => employee.id !== Number(employeeId)) - ); + setEmployeesStore(employeesStore.filter((employee) => employee.id !== Number(employeeId))); }, validate: z.object({ - name: z - .string({ required_error: "Name is required" }) - .nonempty("Name is required"), - age: z - .number({ required_error: "Age is required" }) - .min(18, "Age must be at least 18"), + name: z.string({ required_error: 'Name is required' }).nonempty('Name is required'), + age: z.number({ required_error: 'Age is required' }).min(18, 'Age must be at least 18'), joinDate: z - .string({ required_error: "Join date is required" }) - .nonempty("Join date is required"), - role: z.enum(["Market", "Finance", "Development"], { + .string({ required_error: 'Join date is required' }) + .nonempty('Join date is required'), + role: z.enum(['Market', 'Finance', 'Development'], { errorMap: () => ({ message: 'Role must be "Market", "Finance" or "Development"', }), }), - })["~standard"].validate, + })['~standard'].validate, }; export const employeesCache = new DataSourceCache(); From 08e2dde831bd94ebfc7247e50ebfcaed270f7610 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira <10789765+apedroferreira@users.noreply.github.com> Date: Wed, 26 Mar 2025 16:17:15 +0000 Subject: [PATCH 4/6] Some unrelated adjustments --- .../core/auth-nextjs-themed/next-env.d.ts | 2 +- .../core/auth-nextjs-themed/tsconfig.json | 24 +++++++++++++---- .../DashboardSidebarSubNavigation.tsx | 26 +++++++++---------- pnpm-lock.yaml | 8 +++--- 4 files changed, 37 insertions(+), 23 deletions(-) diff --git a/examples/core/auth-nextjs-themed/next-env.d.ts b/examples/core/auth-nextjs-themed/next-env.d.ts index 40c3d68096c..1b3be0840f3 100644 --- a/examples/core/auth-nextjs-themed/next-env.d.ts +++ b/examples/core/auth-nextjs-themed/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/examples/core/auth-nextjs-themed/tsconfig.json b/examples/core/auth-nextjs-themed/tsconfig.json index 5a1e9c80490..ff197bf4120 100644 --- a/examples/core/auth-nextjs-themed/tsconfig.json +++ b/examples/core/auth-nextjs-themed/tsconfig.json @@ -1,6 +1,10 @@ { "compilerOptions": { - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -18,9 +22,19 @@ } ], "paths": { - "@/*": ["./*"] - } + "@/*": [ + "./*" + ] + }, + "target": "ES2017" }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] } diff --git a/packages/toolpad-core/src/DashboardLayout/DashboardSidebarSubNavigation.tsx b/packages/toolpad-core/src/DashboardLayout/DashboardSidebarSubNavigation.tsx index c33fa6d6862..36ddc36bdea 100644 --- a/packages/toolpad-core/src/DashboardLayout/DashboardSidebarSubNavigation.tsx +++ b/packages/toolpad-core/src/DashboardLayout/DashboardSidebarSubNavigation.tsx @@ -157,19 +157,19 @@ function DashboardSidebarSubNavigation({ const nextItem = subNavigation[navigationItemIndex + 1]; return ( - +
  • + +
  • ); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 004bb81b79d..171b601bfbc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -201,7 +201,7 @@ importers: version: 7.37.4(eslint@8.57.1) eslint-plugin-react-compiler: specifier: latest - version: 19.0.0-beta-3229e95-20250315(eslint@8.57.1) + version: 19.0.0-beta-aeaed83-20250323(eslint@8.57.1) eslint-plugin-react-hooks: specifier: 5.2.0 version: 5.2.0(eslint@8.57.1) @@ -6188,8 +6188,8 @@ packages: peerDependencies: eslint: '>=7.0.0' - eslint-plugin-react-compiler@19.0.0-beta-3229e95-20250315: - resolution: {integrity: sha512-cJL+A3P3nIBAugbZ/RroaixQ6ygnKYMVM1sRnAE26dqHZRVRfqT8+PCyGtB2tgLmQWZhv6glQ+PRoiXqLMcRug==} + eslint-plugin-react-compiler@19.0.0-beta-aeaed83-20250323: + resolution: {integrity: sha512-zkz1RlYTt3zzo7u/O1+5GCXFf75Qwo6guOJQVqjANagc+UoiV4RHyH+HGHQ39h7Nq/QsZG8atCiUS81RMre0UQ==} engines: {node: ^14.17.0 || ^16.0.0 || >= 18.0.0} peerDependencies: eslint: '>=7' @@ -16333,7 +16333,7 @@ snapshots: globals: 13.24.0 rambda: 7.5.0 - eslint-plugin-react-compiler@19.0.0-beta-3229e95-20250315(eslint@8.57.1): + eslint-plugin-react-compiler@19.0.0-beta-aeaed83-20250323(eslint@8.57.1): dependencies: '@babel/core': 7.26.10 '@babel/parser': 7.26.10 From 4b80eb8836558a7fcba7e3f483ac8cd23f89a2b1 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira <10789765+apedroferreira@users.noreply.github.com> Date: Wed, 26 Mar 2025 17:50:19 +0000 Subject: [PATCH 5/6] Fix my own suggestions --- examples/core/auth-nextjs-themed/.env | 1 - .../app/(dashboard)/orders/page.tsx | 3 ++- .../app/components/CustomDataGrid.tsx | 24 +++++++------------ .../theme/customizations/dataDisplay.tsx | 2 -- .../theme/customizations/inputs.tsx | 3 +-- .../auth-nextjs-themed/theme/themeTypes.d.ts | 10 ++++++++ 6 files changed, 21 insertions(+), 22 deletions(-) create mode 100644 examples/core/auth-nextjs-themed/theme/themeTypes.d.ts diff --git a/examples/core/auth-nextjs-themed/.env b/examples/core/auth-nextjs-themed/.env index 856f2860e78..acbad4c5276 100644 --- a/examples/core/auth-nextjs-themed/.env +++ b/examples/core/auth-nextjs-themed/.env @@ -1,3 +1,2 @@ AUTH_SECRET="cNU2IkgN6v9dVQ1EqbCe4Npqh0IbM6VEsMBpg69wiyU=" # Added by `npx auth`. Read more: https://cli.authjs.dev -AUTH_URL="https://r3l69w-3000.csb.app" \ No newline at end of file diff --git a/examples/core/auth-nextjs-themed/app/(dashboard)/orders/page.tsx b/examples/core/auth-nextjs-themed/app/(dashboard)/orders/page.tsx index b0b9b0d84dd..98984370893 100644 --- a/examples/core/auth-nextjs-themed/app/(dashboard)/orders/page.tsx +++ b/examples/core/auth-nextjs-themed/app/(dashboard)/orders/page.tsx @@ -1,7 +1,8 @@ 'use client'; import * as React from 'react'; import CustomDataGrid from '../../components/CustomDataGrid'; +import { rows, columns } from '../../mocks/gridOrdersData'; export default function OrdersPage() { - return ; + return ; } diff --git a/examples/core/auth-nextjs-themed/app/components/CustomDataGrid.tsx b/examples/core/auth-nextjs-themed/app/components/CustomDataGrid.tsx index b6339e2455c..5ffeb9db41a 100644 --- a/examples/core/auth-nextjs-themed/app/components/CustomDataGrid.tsx +++ b/examples/core/auth-nextjs-themed/app/components/CustomDataGrid.tsx @@ -1,33 +1,25 @@ import * as React from 'react'; -import { DataGrid } from '@mui/x-data-grid'; +import { DataGrid, DataGridProps } from '@mui/x-data-grid'; -export default function CustomizedDataGrid({ - rows, - columns, - ...rest -}: { - rows?: any; - columns?: any; -}) { +export default function CustomizedDataGrid(props: DataGridProps) { return (
    (params.indexRelativeToCurrentPage % 2 === 0 ? 'even' : 'odd')} initialState={{ pagination: { paginationModel: { pageSize: 20 } }, }} - sx={(theme) => ({ - borderColor: + sx={{ + ...props.sx, + borderColor: (theme) => theme.palette.mode === 'dark' ? theme.palette.grey[700] : theme.palette.grey[200], '& .MuiDataGrid-cell': { - borderColor: + borderColor: (theme) => theme.palette.mode === 'dark' ? theme.palette.grey[700] : theme.palette.grey[200], }, - })} + }} pageSizeOptions={[10, 20, 50]} disableColumnResize slotProps={{ diff --git a/examples/core/auth-nextjs-themed/theme/customizations/dataDisplay.tsx b/examples/core/auth-nextjs-themed/theme/customizations/dataDisplay.tsx index 05d3bc831ed..e15fdc035ec 100644 --- a/examples/core/auth-nextjs-themed/theme/customizations/dataDisplay.tsx +++ b/examples/core/auth-nextjs-themed/theme/customizations/dataDisplay.tsx @@ -235,11 +235,9 @@ export const dataDisplayCustomizations: Components = { }, }, }, - // @ts-expect-error MuiDataGrid: { styleOverrides: { root: () => ({ - // ... existing code ... '&.MuiDataGrid-root--densityCompact .MuiDataGrid-actionsCell button': { width: '28px', height: '28px', diff --git a/examples/core/auth-nextjs-themed/theme/customizations/inputs.tsx b/examples/core/auth-nextjs-themed/theme/customizations/inputs.tsx index fb6a5712274..22c53b5fc16 100644 --- a/examples/core/auth-nextjs-themed/theme/customizations/inputs.tsx +++ b/examples/core/auth-nextjs-themed/theme/customizations/inputs.tsx @@ -370,7 +370,7 @@ export const inputsCustomizations: Components = { styleOverrides: { root: { border: 'none', - marginTop: 8, + marginTop: 6, }, input: { '&::placeholder': { @@ -452,7 +452,6 @@ export const inputsCustomizations: Components = { styleOverrides: { root: ({ theme }) => ({ typography: theme.typography.caption, - marginTop: 8, }), }, }, diff --git a/examples/core/auth-nextjs-themed/theme/themeTypes.d.ts b/examples/core/auth-nextjs-themed/theme/themeTypes.d.ts new file mode 100644 index 00000000000..fcfb2b39b80 --- /dev/null +++ b/examples/core/auth-nextjs-themed/theme/themeTypes.d.ts @@ -0,0 +1,10 @@ +import { GridComponentsPropsOverrides } from '@mui/x-data-grid/models/props/GridProps'; + +declare module '@mui/material/styles' { + interface Components { + MuiDataGrid?: { + defaultProps?: Partial; + styleOverrides?: Record; + }; + } +} From c1382226cbc5d7e7ca41e2cee2e1095c69fba202 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira <10789765+apedroferreira@users.noreply.github.com> Date: Wed, 26 Mar 2025 17:55:18 +0000 Subject: [PATCH 6/6] Refix .env --- examples/core/auth-nextjs-themed/.env | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/core/auth-nextjs-themed/.env b/examples/core/auth-nextjs-themed/.env index acbad4c5276..856f2860e78 100644 --- a/examples/core/auth-nextjs-themed/.env +++ b/examples/core/auth-nextjs-themed/.env @@ -1,2 +1,3 @@ AUTH_SECRET="cNU2IkgN6v9dVQ1EqbCe4Npqh0IbM6VEsMBpg69wiyU=" # Added by `npx auth`. Read more: https://cli.authjs.dev +AUTH_URL="https://r3l69w-3000.csb.app" \ No newline at end of file