Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,91 @@
});
});

it('should fetch current value using getList when optionValue is not id', async () => {
const children = jest.fn().mockReturnValue(<p>child</p>);
const optionValue = 'login';
const currentUser = { id: 2, login: 'jdoe', name: 'Jane Doe' };
const dataProvider = testDataProvider({
getList: jest
.fn()
.mockResolvedValueOnce({
data: [{ id: 1, login: 'asmith', name: 'Alice Smith' }],
total: 1,
})
.mockResolvedValueOnce({
data: [currentUser],
total: 1,
}),
getMany: jest.fn(),
});

render(
<CoreAdminContext dataProvider={dataProvider}>
<Form defaultValues={{ owner: 'jdoe' }}>
<ReferenceInputController
reference="users"
resource="comments"
source="owner"
optionValue={optionValue}
>
{children}
</ReferenceInputController>
</Form>
</CoreAdminContext>
);

await waitFor(() => {
expect(dataProvider.getList).toHaveBeenCalledTimes(2);
expect(dataProvider.getMany).not.toHaveBeenCalled();
});

expect(dataProvider.getList).toHaveBeenNthCalledWith(
1,
'users',
expect.objectContaining({
filter: {},
meta: undefined,
pagination: {
page: 1,
perPage: 25,
},
sort: {
field: 'id',
order: 'ASC',
},
signal: undefined,
})
);
expect(dataProvider.getList).toHaveBeenNthCalledWith(
2,
'users',
expect.objectContaining({
filter: { login: 'jdoe' },
pagination: {
page: 1,
perPage: 1,
},
sort: {
field: 'id',
order: 'DESC',
},
signal: undefined,
})
);

await waitFor(() => {
expect(children).toHaveBeenCalledWith(
expect.objectContaining({
allChoices: [currentUser, { id: 1, login: 'asmith', name: 'Alice Smith' }],

Check failure on line 218 in packages/ra-core/src/controller/input/useReferenceInputController.spec.tsx

View workflow job for this annotation

GitHub Actions / typecheck

Replace `currentUser,·{·id:·1,·login:·'asmith',·name:·'Alice·Smith'·}` with `⏎························currentUser,⏎························{·id:·1,·login:·'asmith',·name:·'Alice·Smith'·},⏎····················`
availableChoices: [{ id: 1, login: 'asmith', name: 'Alice Smith' }],

Check failure on line 219 in packages/ra-core/src/controller/input/useReferenceInputController.spec.tsx

View workflow job for this annotation

GitHub Actions / typecheck

Replace `{·id:·1,·login:·'asmith',·name:·'Alice·Smith'·}` with `⏎························{·id:·1,·login:·'asmith',·name:·'Alice·Smith'·},⏎····················`
selectedChoices: [currentUser],
total: 2,
isFromReference: true,
})
);
});
});

it('should not fetch current value using getMany if it is empty', async () => {
const children = jest.fn().mockReturnValue(<p>child</p>);
render(
Expand Down
103 changes: 90 additions & 13 deletions packages/ra-core/src/controller/input/useReferenceInputController.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useWatch } from 'react-hook-form';
import { keepPreviousData, type UseQueryOptions } from '@tanstack/react-query';
import get from 'lodash/get.js';

import { useGetList } from '../../dataProvider';
import { useReference } from '../useReference';
Expand Down Expand Up @@ -58,6 +59,7 @@
filter,
page: initialPage = 1,
perPage: initialPerPage = 25,
optionValue = 'id',
sort: initialSort,
queryOptions = {},
reference,
Expand All @@ -77,6 +79,8 @@
// selection logic
const finalSource = useWrappedSource(source);
const currentValue = useWatch({ name: finalSource });
const currentValueEnabled = currentValue != null && currentValue !== '';
const useOptionValueLookup = optionValue !== 'id';

const isGetMatchingEnabled = enableGetChoices
? enableGetChoices(params.filterValues)
Expand Down Expand Up @@ -116,7 +120,38 @@

// fetch current value
const {
referenceRecord: currentReferenceRecord,
data: currentReferenceRecords,
refetch: refetchCurrentReference,
error: errorCurrentReference,
isLoading: isLoadingCurrentReference,
isFetching: isFetchingCurrentReference,
isPaused: isPausedCurrentReference,
isPending: isPendingCurrentReference,
isPlaceholderData: isPlaceholderDataCurrentReference,
} = useGetList<RecordType>(
reference,
{
pagination: {
page: 1,
perPage: 1,
},
sort: { field: 'id', order: 'DESC' },
filter: useOptionValueLookup

Check failure on line 139 in packages/ra-core/src/controller/input/useReferenceInputController.ts

View workflow job for this annotation

GitHub Actions / typecheck

Replace `⏎················?·{·[optionValue]:·currentValue·}⏎···············` with `·?·{·[optionValue]:·currentValue·}`
? { [optionValue]: currentValue }
: {},
meta,
},
{
enabled: useOptionValueLookup && currentValueEnabled,
placeholderData: keepPreviousData,
...(otherQueryOptions as UseQueryOptions<
GetListResult<RecordType>
>),
}
);

const {
referenceRecord: currentReferenceRecordById,
refetch: refetchReference,
error: errorReference,
isLoading: isLoadingReference,
Expand All @@ -129,18 +164,28 @@
reference,
// @ts-ignore the types of the queryOptions for the getMAny and getList are not compatible
options: {
enabled: currentValue != null && currentValue !== '',
enabled: !useOptionValueLookup && currentValueEnabled,
meta,
...otherQueryOptions,
},
});

const currentReferenceRecord = useOptionValueLookup
? currentReferenceRecords?.[0]
: currentReferenceRecordById;

const isPending =
// The reference query isn't enabled when there is no value yet but as it has no data, react-query will flag it as pending
(currentValue != null && currentValue !== '' && isPendingReference) ||
(currentValueEnabled &&
(useOptionValueLookup
? isPendingCurrentReference
: isPendingReference)) ||
isPendingPossibleValues;

const isPaused = isPausedReference || isPausedPossibleValues;
const isPaused =
(useOptionValueLookup

Check failure on line 186 in packages/ra-core/src/controller/input/useReferenceInputController.ts

View workflow job for this annotation

GitHub Actions / typecheck

Replace `⏎············?·isPausedCurrentReference⏎············:·isPausedReference)·||` with `·?·isPausedCurrentReference·:·isPausedReference)·||⏎·······`
? isPausedCurrentReference
: isPausedReference) || isPausedPossibleValues;

// We need to delay the update of the referenceRecord and the finalData
// to the next React state update, because otherwise it can raise a warning
Expand All @@ -164,14 +209,17 @@
referenceRecord == null ||
possibleValuesData == null ||
(possibleValuesData ?? []).find(
record => record.id === referenceRecord.id
record =>
get(record, optionValue) === get(referenceRecord, optionValue)

Check failure on line 213 in packages/ra-core/src/controller/input/useReferenceInputController.ts

View workflow job for this annotation

GitHub Actions / typecheck

Insert `⏎···················`
)
) {
// Here we might have the referenceRecord but no data (because of enableGetChoices for instance)
const finalData = possibleValuesData ?? [];
if (
referenceRecord &&
finalData.find(r => r.id === referenceRecord.id) == null
finalData.find(
r => get(r, optionValue) === get(referenceRecord, optionValue)

Check failure on line 221 in packages/ra-core/src/controller/input/useReferenceInputController.ts

View workflow job for this annotation

GitHub Actions / typecheck

Replace `·get(r,·optionValue)·===` with `⏎························get(r,·optionValue)·===⏎·······················`
) == null
) {
finalData.push(referenceRecord);
}
Expand All @@ -186,12 +234,21 @@
finalTotal: total == null ? undefined : total + 1,
};
}
}, [isPaused, referenceRecord, possibleValuesData, total]);

Check warning on line 237 in packages/ra-core/src/controller/input/useReferenceInputController.ts

View workflow job for this annotation

GitHub Actions / typecheck

React Hook useMemo has a missing dependency: 'optionValue'. Either include it or remove the dependency array

const refetch = useCallback(() => {
refetchGetList();
refetchReference();
}, [refetchGetList, refetchReference]);
if (useOptionValueLookup) {
refetchCurrentReference();
} else {
refetchReference();
}
}, [
refetchCurrentReference,
refetchGetList,
refetchReference,
useOptionValueLookup,
]);

const currentSort = useMemo(
() => ({
Expand All @@ -211,16 +268,27 @@
// TODO v6: same as above
selectedChoices: referenceRecord ? [referenceRecord] : [],
displayedFilters: params.displayedFilters,
error: errorReference || errorPossibleValues,
error:
(useOptionValueLookup
? errorCurrentReference
: errorReference) || errorPossibleValues,
filter: params.filter,
filterValues: params.filterValues,
hideFilter: paramsModifiers.hideFilter,
isFetching: isFetchingReference || isFetchingPossibleValues,
isLoading: isLoadingReference || isLoadingPossibleValues,
isPaused: isPausedReference || isPausedPossibleValues,
isFetching:
(useOptionValueLookup
? isFetchingCurrentReference
: isFetchingReference) || isFetchingPossibleValues,
isLoading:
(useOptionValueLookup
? isLoadingCurrentReference
: isLoadingReference) || isLoadingPossibleValues,
isPaused,
isPending,
isPlaceholderData:
isPlaceholderDataReference ||
(useOptionValueLookup
? isPlaceholderDataCurrentReference
: isPlaceholderDataReference) ||
isPlaceholderDataPossibleValues,
page: params.page,
perPage: params.perPage,
Expand All @@ -244,19 +312,25 @@
: params.page > 1,
isFromReference: true,
}) as ChoicesContextValue<RecordType>,
[

Check warning on line 315 in packages/ra-core/src/controller/input/useReferenceInputController.ts

View workflow job for this annotation

GitHub Actions / typecheck

React Hook useMemo has a missing dependency: 'isPaused'. Either include it or remove the dependency array
currentSort,
errorCurrentReference,
errorPossibleValues,
errorReference,
finalData,
finalTotal,
isFetchingCurrentReference,
isFetchingPossibleValues,
isFetchingReference,
isLoadingCurrentReference,
isLoadingPossibleValues,
isLoadingReference,
isPausedCurrentReference,
isPausedPossibleValues,
isPausedReference,
isPending,
isPendingCurrentReference,
isPlaceholderDataCurrentReference,
isPlaceholderDataReference,
isPlaceholderDataPossibleValues,
pageInfo,
Expand All @@ -277,6 +351,8 @@
refetch,
source,
total,
useOptionValueLookup,
optionValue,
]
);
};
Expand All @@ -296,6 +372,7 @@
> & { meta?: any };
page?: number;
perPage?: number;
optionValue?: string;
record?: RaRecord;
reference: string;
resource?: string;
Expand Down
Loading