Repository: api-platform/admin
Pull request #495 (2023-02-13 11:35:25)

FieldGuesser: props passing to SingleFieldList  (linkType prop)
By default any reference field links to edit view. 

To change it RA uses  [`link` prop](https://marmelab.com/react-admin/ReferenceField.html#link) for single field and [`linkType` prop](https://marmelab.com/react-admin/SingleFieldList.html#linktype) for array.

So that works fine:
```
<FieldGuesser source={"user"} link={"show"} />
```

But for array it doesn't because nested `SimpeFieldList` component does't get its prop:
```
<FieldGuesser source={"users"} linkType={"show"} />
```
So the only solution for that is to skip using FieldGuesser for arrays and write it by hand.

IHMO it is good to unify that and support it in both cases by FieldGuesser especially that it is very common use case to have all relations linked to show pages. 

alanpoulain: CI seems to fail, I need some time to dig the issue, feel free to do it if you want :slightly_smiling_face: 
PawelSuwinski: Checks solved, so what about merging it?

Patch:
diff --git a/src/FieldGuesser.tsx b/src/FieldGuesser.tsx
index 90e123d..d715d81 100644
--- a/src/FieldGuesser.tsx
+++ b/src/FieldGuesser.tsx
@@ -23,6 +23,7 @@ import type {
   NumberFieldProps,
   ReferenceArrayFieldProps,
   ReferenceFieldProps,
+  SingleFieldListProps,
   TextFieldProps,
   UrlFieldProps,
 } from 'react-admin';
@@ -65,11 +66,13 @@ const renderField = (
     }
 
     const fieldName = schemaAnalyzer.getFieldNameFromSchema(field.reference);
+    const { linkType, ...rest } = props as ReferenceArrayFieldProps &
+      Pick<SingleFieldListProps, 'linkType'>;
     return (
       <ReferenceArrayField
-        {...(props as ReferenceArrayFieldProps)}
+        {...(rest as ReferenceArrayFieldProps)}
         reference={field.reference.name}>
-        <SingleFieldList>
+        <SingleFieldList linkType={linkType}>
           <ChipField source={fieldName} key={fieldName} />
         </SingleFieldList>
       </ReferenceArrayField>
diff --git a/src/ListGuesser.tsx b/src/ListGuesser.tsx
index 6583f90..9d24464 100644
--- a/src/ListGuesser.tsx
+++ b/src/ListGuesser.tsx
@@ -70,6 +70,7 @@ export const IntrospectedListGuesser = ({
   empty,
   hover,
   expand,
+  expandSingle,
   optimized,
   size,
   children,
@@ -122,6 +123,7 @@ export const IntrospectedListGuesser = ({
         empty={empty}
         hover={hover}
         expand={expand}
+        expandSingle={expandSingle}
         optimized={optimized}
         size={size}
         sx={datagridSx}>
diff --git a/src/hydra/dataProvider.ts b/src/hydra/dataProvider.ts
index bf1ff01..385ada4 100644
--- a/src/hydra/dataProvider.ts
+++ b/src/hydra/dataProvider.ts
@@ -388,7 +388,9 @@ function dataProvider(
         } = params as GetListParams | GetManyReferenceParams;
 
         if (order && field) {
-          url.searchParams.set(`order[${field}]`, order);
+          field.split(',').forEach((fieldName) => {
+            url.searchParams.set(`order[${fieldName.trim()}]`, order);
+          });
         }
         if (page) url.searchParams.set('page', page.toString());
         if (perPage) url.searchParams.set('itemsPerPage', perPage.toString());
diff --git a/src/types.ts b/src/types.ts
index 30032f7..25124da 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -47,6 +47,7 @@ import type {
   ResourceProps,
   ShowProps,
   SimpleFormProps,
+  SingleFieldListProps,
   TabbedFormProps,
   TextFieldProps,
   TextInputProps,
@@ -452,7 +453,7 @@ export type FieldProps =
   | UrlFieldProps
   | EmailFieldProps
   | ArrayFieldProps
-  | ReferenceArrayFieldProps
+  | (ReferenceArrayFieldProps & Pick<SingleFieldListProps, 'linkType'>)
   | EnumFieldProps
   | ReferenceFieldProps;
 


Test patch:
diff --git a/src/hydra/dataProvider.test.ts b/src/hydra/dataProvider.test.ts
index 1d07e17..874ab8a 100644
--- a/src/hydra/dataProvider.test.ts
+++ b/src/hydra/dataProvider.test.ts
@@ -603,4 +603,45 @@ describe('Transform a React Admin request to an Hydra request', () => {
       'http://localhost/entrypoint/comments?order%5Bid%5D=ASC&page=1&itemsPerPage=30',
     );
   });
+
+  test('React Admin get list with compound order', async () => {
+    mockFetchHydra.mockClear();
+    mockFetchHydra.mockReturnValueOnce(
+      Promise.resolve({
+        status: 200,
+        headers: new Headers(),
+        json: {
+          'hydra:member': [
+            { '@id': '/comments/423' },
+            { '@id': '/comments/976' },
+          ],
+          'hydra:totalItems': 2,
+          'hydra:view': {
+            '@id': '/comments?page=1',
+            '@type': 'hydra:PartialCollectionView',
+            'hydra:first': '/comments?page=1',
+            'hydra:last': '/comments?page=1',
+            'hydra:next': '/comments?page=1',
+          },
+        },
+      }),
+    );
+    const result = await dataProvider.current.getList('comments', {
+      pagination: { page: 1, perPage: 30 },
+      sort: { field: 'text, id', order: 'DESC' },
+      filter: false,
+    });
+    expect(result).toEqual({
+      data: [
+        { '@id': '/comments/423', id: '/comments/423' },
+        { '@id': '/comments/976', id: '/comments/976' },
+      ],
+      total: 2,
+    });
+    const url = mockFetchHydra.mock.calls?.[0]?.[0] ?? new URL('https://foo');
+    expect(url).toBeInstanceOf(URL);
+    expect(url.toString()).toEqual(
+      'http://localhost/entrypoint/comments?order%5Btext%5D=DESC&order%5Bid%5D=DESC&page=1&itemsPerPage=30',
+    );
+  });
 });