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

Fix <Datagrid> rowClick function cannot expand or select #10404

Merged
merged 2 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
59 changes: 57 additions & 2 deletions packages/ra-ui-materialui/src/list/datagrid/Datagrid.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,11 @@ export const RowClickFalse = () => (

const dataProvider = fakeRestDataProvider({ books: data });

export const FullApp = () => (
export const FullApp = ({
rowClick,
}: {
rowClick?: DatagridRowProps['rowClick'];
}) => (
<AdminContext
dataProvider={dataProvider}
i18nProvider={polyglotI18nProvider(() => defaultMessages, 'en')}
Expand All @@ -481,7 +485,10 @@ export const FullApp = () => (
name="books"
list={() => (
<List>
<Datagrid>
<Datagrid
expand={<ExpandDetails />}
rowClick={rowClick}
>
<TextField source="id" />
<TextField source="title" />
<TextField source="author" />
Expand All @@ -490,11 +497,59 @@ export const FullApp = () => (
</List>
)}
edit={EditGuesser}
show={ShowGuesser}
/>
</AdminUI>
</AdminContext>
);

FullApp.argTypes = {
rowClick: {
options: [
'inferred',
'show',
'edit',
'no-link',
'expand',
'toggleSelection',
'function to expand',
'function to toggleSelection',
],
mapping: {
inferred: undefined,
show: 'show',
edit: 'edit',
'no-link': false,
expand: 'expand',
toggleSelection: 'toggleSelection',
'function to expand': (id, resource, record) => {
if (process.env.NODE_ENV === 'development') {
console.log('function to expand', id, resource, record);
}
return 'expand';
},
'function to toggleSelection': (id, resource, record) => {
if (process.env.NODE_ENV === 'development') {
console.log(
'function to toggleSelection',
id,
resource,
record
);
}
return 'toggleSelection';
},
},
control: { type: 'select' },
},
};

const ExpandDetails = () => {
const record = useRecordContext();

return <div>Expand: {record?.title}</div>;
};

const MyDatagridRow = ({
onToggleItem,
children,
Expand Down
254 changes: 153 additions & 101 deletions packages/ra-ui-materialui/src/list/datagrid/DatagridRow.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,119 +98,171 @@ describe('<DatagridRow />', () => {
};

describe('rowClick', () => {
it("should redirect to edit page if the 'edit' option is selected", async () => {
let spy = jest.fn();
render(
<LocationSpy spy={spy}>
<RecordContextProvider value={defaultRecord}>
<DatagridRow {...defaultProps} rowClick="edit">
<TitleField />
</DatagridRow>
</RecordContextProvider>
</LocationSpy>
);
const cell = screen.getByText('hello');
const row = cell.closest('tr');
if (!row) {
throw new Error('row not found');
it.each([
{ rowClick: 'edit', description: 'passed directly' },
{
rowClick: () => 'edit',
description: 'from a rowClick function',
},
{
rowClick: async () => 'edit',
description: 'from an async rowClick function',
},
])(
"should redirect to edit page if the 'edit' option is $description",
async ({ rowClick }) => {
let spy = jest.fn();
render(
<LocationSpy spy={spy}>
<RecordContextProvider value={defaultRecord}>
<DatagridRow {...defaultProps} rowClick={rowClick}>
<TitleField />
</DatagridRow>
</RecordContextProvider>
</LocationSpy>
);
const cell = screen.getByText('hello');
const row = cell.closest('tr');
if (!row) {
throw new Error('row not found');
}
expect(
row.classList.contains('RaDatagrid-clickableRow')
).toBeTruthy();
fireEvent.click(row);

await waitFor(() => {
expect(spy).toHaveBeenCalledWith(
expect.objectContaining({ pathname: '/posts/15' })
);
});
}
expect(
row.classList.contains('RaDatagrid-clickableRow')
).toBeTruthy();
fireEvent.click(row);
);

await waitFor(() => {
expect(spy).toHaveBeenCalledWith(
expect.objectContaining({ pathname: '/posts/15' })
it.each([
{ rowClick: 'show', description: 'passed directly' },
{
rowClick: () => 'show',
description: 'from a rowClick function',
},
{
rowClick: async () => 'show',
description: 'from an async rowClick function',
},
])(
"should redirect to show page if the 'show' option is $description",
async ({ rowClick }) => {
let spy = jest.fn();
render(
<LocationSpy spy={spy}>
<RecordContextProvider value={defaultRecord}>
<DatagridRow {...defaultProps} rowClick={rowClick}>
<TitleField />
</DatagridRow>
</RecordContextProvider>
</LocationSpy>
);
});
});
const cell = screen.getByText('hello');
const row = cell.closest('tr');
if (!row) {
throw new Error('row not found');
}
expect(
row.classList.contains('RaDatagrid-clickableRow')
).toBeTruthy();
fireEvent.click(row);

it("should redirect to show page if the 'show' option is selected", async () => {
let spy = jest.fn();
render(
<LocationSpy spy={spy}>
await waitFor(() => {
expect(spy).toHaveBeenCalledWith(
expect.objectContaining({ pathname: '/posts/15/show' })
);
});
}
);

it.each([
{ rowClick: 'expand', description: 'passed directly' },
{
rowClick: () => 'expand',
description: 'from a rowClick function',
},
{
rowClick: async () => 'expand',
description: 'from an async rowClick function',
},
])(
"should change the expand state if the 'expand' option is $description",
async ({ rowClick }) => {
render(
<RecordContextProvider value={defaultRecord}>
<DatagridRow {...defaultProps} rowClick="show">
<DatagridRow
{...defaultProps}
rowClick={rowClick}
expand={<ExpandPanel />}
>
<TitleField />
</DatagridRow>
</RecordContextProvider>
</LocationSpy>
);
const cell = screen.getByText('hello');
const row = cell.closest('tr');
if (!row) {
throw new Error('row not found');
}
expect(
row.classList.contains('RaDatagrid-clickableRow')
).toBeTruthy();
fireEvent.click(row);

await waitFor(() => {
expect(spy).toHaveBeenCalledWith(
expect.objectContaining({ pathname: '/posts/15/show' })
);
});
});

it("should change the expand state if the 'expand' option is selected", async () => {
render(
<RecordContextProvider value={defaultRecord}>
<DatagridRow
{...defaultProps}
rowClick="expand"
expand={<ExpandPanel />}
>
<TitleField />
</DatagridRow>
</RecordContextProvider>
);
expect(screen.queryAllByText('expanded')).toHaveLength(0);
const cell = screen.getByText('hello');
const row = cell.closest('tr');
if (!row) {
throw new Error('row not found');
}
expect(
row.classList.contains('RaDatagrid-clickableRow')
).toBeTruthy();
fireEvent.click(row);
await waitFor(() => {
expect(screen.queryAllByText('expanded')).toHaveLength(1);
});
fireEvent.click(row);
await waitFor(() => {
expect(screen.queryAllByText('expanded')).toHaveLength(0);
});
});
const cell = screen.getByText('hello');
const row = cell.closest('tr');
if (!row) {
throw new Error('row not found');
}
expect(
row.classList.contains('RaDatagrid-clickableRow')
).toBeTruthy();
fireEvent.click(row);
await waitFor(() => {
expect(screen.queryAllByText('expanded')).toHaveLength(1);
});
fireEvent.click(row);
await waitFor(() => {
expect(screen.queryAllByText('expanded')).toHaveLength(0);
});
}
);

it("should execute the onToggleItem function if the 'toggleSelection' option is selected", async () => {
const onToggleItem = jest.fn();
render(
<RecordContextProvider value={defaultRecord}>
<DatagridRow
{...defaultProps}
onToggleItem={onToggleItem}
rowClick="toggleSelection"
>
<TitleField />
</DatagridRow>
</RecordContextProvider>
);
const cell = screen.getByText('hello');
const row = cell.closest('tr');
if (!row) {
throw new Error('row not found');
it.each([
{ rowClick: 'toggleSelection', description: 'passed directly' },
{
rowClick: () => 'toggleSelection',
description: 'from a rowClick function',
},
{
rowClick: async () => 'toggleSelection',
description: 'from an async rowClick function',
},
])(
"should execute the onToggleItem function if the 'toggleSelection' option is $description",
async ({ rowClick }) => {
const onToggleItem = jest.fn();
render(
<RecordContextProvider value={defaultRecord}>
<DatagridRow
{...defaultProps}
onToggleItem={onToggleItem}
rowClick={rowClick}
>
<TitleField />
</DatagridRow>
</RecordContextProvider>
);
const cell = screen.getByText('hello');
const row = cell.closest('tr');
if (!row) {
throw new Error('row not found');
}
expect(
row.classList.contains('RaDatagrid-clickableRow')
).toBeTruthy();
fireEvent.click(row);
await waitFor(() => {
expect(onToggleItem.mock.calls.length).toEqual(1);
});
}
expect(
row.classList.contains('RaDatagrid-clickableRow')
).toBeTruthy();
fireEvent.click(row);
await waitFor(() => {
expect(onToggleItem.mock.calls.length).toEqual(1);
});
});
);

it('should not execute the onToggleItem function if the row is not selectable', () => {
const onToggleItem = jest.fn();
Expand Down
Loading
Loading