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

[RFR] Fix ReferenceArrayInput does not work in Filters #3898

Merged
merged 1 commit into from
Oct 29, 2019
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
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useMemo, useState, useEffect, useRef } from 'react';
import isEqual from 'lodash/isEqual';
import difference from 'lodash/difference';
import { Record, Pagination, Sort } from '../../types';
import { Pagination, Record, Sort } from '../../types';
import { useGetMany } from '../../dataProvider';
import { FieldInputProps } from 'react-final-form';
import useGetMatching from '../../dataProvider/useGetMatching';
Expand All @@ -13,7 +13,7 @@ import { getStatusForArrayInput as getDataStatus } from './referenceDataStatus';
*
* @example
*
* const { choices, error, loaded, loading, referenceBasePath } = useReferenceArrayInputController({
* const { choices, error, loaded, loading } = useReferenceArrayInputController({
* basePath: 'resource';
* record: { referenceIds: ['id1', 'id2']};
* reference: 'reference';
Expand All @@ -33,7 +33,6 @@ import { getStatusForArrayInput as getDataStatus } from './referenceDataStatus';
* @return {Object} controllerProps Fetched data and callbacks for the ReferenceArrayInput components
*/
const useReferenceArrayInputController = ({
basePath,
filter: defaultFilter,
filterToQuery = defaultFilterToQuery,
input,
Expand Down Expand Up @@ -115,7 +114,7 @@ const useReferenceArrayInputController = ({
// the component displaying the currently selected records may fail
const finalMatchingReferences =
matchingReferences && matchingReferences.length > 0
? matchingReferences.concat(finalReferenceRecords)
? mergeReferences(matchingReferences, finalReferenceRecords)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was creating warnings about duplicate keys: selected values that were also in the list of possible choices were displayed twice!

: finalReferenceRecords.length > 0
? finalReferenceRecords
: matchingReferences;
Expand All @@ -127,20 +126,31 @@ const useReferenceArrayInputController = ({
translate,
});

const referenceBasePath = basePath.replace(resource, reference); // FIXME obviously very weak
return {
choices: dataStatus.choices,
error: dataStatus.error,
loaded,
loading: dataStatus.waiting,
referenceBasePath,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is never used by child components. It was not passed in 2.0. I think it comes from a bad copy/paste of ReferenceArrayField during the hooks refactoring.

setFilter,
setPagination,
setSort,
warning: dataStatus.warning,
};
};

// concatenate and deduplicate two lists of records
const mergeReferences = (ref1: Record[], ref2: Record[]): Record[] => {
const res = [...ref1];
const ids = ref1.map(ref => ref.id);
ref2.forEach(ref => {
if (!ids.includes(ref.id)) {
ids.push(ref.id);
res.push(ref);
}
});
return res;
};

export default useReferenceArrayInputController;

/**
Expand All @@ -151,15 +161,13 @@ export default useReferenceArrayInputController;
* @property {Object} error the error returned by the dataProvider
* @property {boolean} loading is the reference currently loading
* @property {boolean} loaded has the reference already been loaded
* @property {string} referenceBasePath basePath of the reference
*/
interface ReferenceArrayInputProps {
choices: Record[];
error?: any;
warning?: any;
loading: boolean;
loaded: boolean;
referenceBasePath: string;
setFilter: (filter: any) => void;
setPagination: (pagination: Pagination) => void;
setSort: (sort: Sort) => void;
Expand Down
15 changes: 12 additions & 3 deletions packages/ra-core/src/dataProvider/useGetMany.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import union from 'lodash/union';
import isEqual from 'lodash/isEqual';

import { CRUD_GET_MANY } from '../actions/dataActions/crudGetMany';
import { Identifier, ReduxState, DataProviderProxy } from '../types';
import { Identifier, Record, ReduxState, DataProviderProxy } from '../types';
import { useSafeSetState } from '../util/hooks';
import useDataProvider from './useDataProvider';
import { useEffect } from 'react';
Expand All @@ -23,7 +23,12 @@ interface Query {
interface QueriesToCall {
[resource: string]: Query[];
}

interface UseGetManyResult {
data: Record[];
error?: any;
loading: boolean;
loaded: boolean;
}
let queriesToCall: QueriesToCall = {};
let dataProvider: DataProviderProxy;

Expand Down Expand Up @@ -74,7 +79,11 @@ const DataProviderOptions = { action: CRUD_GET_MANY };
* );
* };
*/
const useGetMany = (resource: string, ids: Identifier[], options: any = {}) => {
const useGetMany = (
resource: string,
ids: Identifier[],
options: any = {}
): UseGetManyResult => {
// we can't use useQueryWithStore here because we're aggregating queries first
// therefore part of the useQueryWithStore logic will have to be repeated below
const selectMany = useMemo(makeGetManySelector, []);
Expand Down
13 changes: 11 additions & 2 deletions packages/ra-core/src/dataProvider/useGetMatching.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useSelector } from 'react-redux';
import { CRUD_GET_MATCHING } from '../actions/dataActions/crudGetMatching';
import { Pagination, Sort, ReduxState } from '../types';
import { Identifier, Pagination, Sort, Record, ReduxState } from '../types';
import useQueryWithStore from './useQueryWithStore';
import {
getReferenceResource,
Expand Down Expand Up @@ -66,7 +66,7 @@ const useGetMatching = (
source: string,
referencingResource: string,
options?: any
) => {
): UseGetMatchingResult => {
const relatedTo = referenceSource(referencingResource, source);
const {
data: possibleValues,
Expand Down Expand Up @@ -119,4 +119,13 @@ const useGetMatching = (
};
};

interface UseGetMatchingResult {
data: Record[];
ids: Identifier[];
total: number;
error?: any;
loading: boolean;
loaded: boolean;
}

export default useGetMatching;
Loading