mirror of
				https://github.com/strapi/strapi.git
				synced 2025-11-04 11:54:10 +00:00 
			
		
		
		
	Merge pull request #14527 from strapi/relations/fix-order-normalizeRelations
[Relations - Front] Reverse order of relations
This commit is contained in:
		
						commit
						541b1695fe
					
				@ -7,7 +7,7 @@ import { useCMEditViewDataManager, NotAllowedInput, useQueryParams } from '@stra
 | 
			
		||||
 | 
			
		||||
import { RelationInput } from '../RelationInput';
 | 
			
		||||
import { useRelation } from '../../hooks/useRelation';
 | 
			
		||||
import { connect, select, normalizeRelations } from './utils';
 | 
			
		||||
import { connect, select, normalizeRelations, normalizeSearchResults } from './utils';
 | 
			
		||||
import { PUBLICATION_STATES, RELATIONS_TO_DISPLAY, SEARCH_RESULTS_TO_DISPLAY } from './constants';
 | 
			
		||||
import { getTrad } from '../../utils';
 | 
			
		||||
 | 
			
		||||
@ -194,9 +194,8 @@ export const RelationInputDataManager = ({
 | 
			
		||||
      }}
 | 
			
		||||
      relations={normalizedRelations}
 | 
			
		||||
      required={required}
 | 
			
		||||
      searchResults={normalizeRelations(search, {
 | 
			
		||||
      searchResults={normalizeSearchResults(search, {
 | 
			
		||||
        mainFieldName: mainField.name,
 | 
			
		||||
        search: 'search',
 | 
			
		||||
      })}
 | 
			
		||||
      size={size}
 | 
			
		||||
    />
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,4 @@
 | 
			
		||||
export { default as connect } from './connect';
 | 
			
		||||
export { default as select } from './select';
 | 
			
		||||
export { normalizeRelations } from './normalizeRelations';
 | 
			
		||||
export { normalizeSearchResults } from './normalizeSearchResults';
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ import { getRelationLink } from './getRelationLink';
 | 
			
		||||
 | 
			
		||||
import { PUBLICATION_STATES } from '../constants';
 | 
			
		||||
 | 
			
		||||
const normalizeRelation = (relation, { shouldAddLink, mainFieldName, targetModel }) => {
 | 
			
		||||
export const normalizeRelation = (relation, { shouldAddLink, mainFieldName, targetModel }) => {
 | 
			
		||||
  const nextRelation = { ...relation };
 | 
			
		||||
 | 
			
		||||
  if (shouldAddLink) {
 | 
			
		||||
@ -22,6 +22,14 @@ const normalizeRelation = (relation, { shouldAddLink, mainFieldName, targetModel
 | 
			
		||||
  return nextRelation;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Applies some transformations to existing and new relations in order to display them correctly
 | 
			
		||||
 * relations: raw relations data coming from useRelations
 | 
			
		||||
 * shouldAddLink: comes from generateRelationQueryInfos, if true we display a link to the relation (TO FIX: explanation)
 | 
			
		||||
 * mainFieldName: name of the main field inside the relation (e.g. text field), if no displayable main field exists (e.g. date field) we use the id of the entry
 | 
			
		||||
 * targetModel: the model on which the relation is based on, used to create an URL link
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export const normalizeRelations = (
 | 
			
		||||
  relations,
 | 
			
		||||
  { modifiedData = {}, shouldAddLink = false, mainFieldName, targetModel }
 | 
			
		||||
@ -31,7 +39,7 @@ export const normalizeRelations = (
 | 
			
		||||
    data: {
 | 
			
		||||
      pages:
 | 
			
		||||
        [
 | 
			
		||||
          ...(relations?.data?.pages ?? []),
 | 
			
		||||
          ...(relations?.data?.pages.reverse() ?? []),
 | 
			
		||||
          ...(modifiedData?.connect ? [{ results: modifiedData.connect }] : []),
 | 
			
		||||
        ]
 | 
			
		||||
          ?.map((page) =>
 | 
			
		||||
@ -44,7 +52,6 @@ export const normalizeRelations = (
 | 
			
		||||
              )
 | 
			
		||||
              .map((relation) =>
 | 
			
		||||
                normalizeRelation(relation, {
 | 
			
		||||
                  modifiedData,
 | 
			
		||||
                  shouldAddLink,
 | 
			
		||||
                  mainFieldName,
 | 
			
		||||
                  targetModel,
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,12 @@
 | 
			
		||||
import { normalizeRelation } from './normalizeRelations';
 | 
			
		||||
 | 
			
		||||
export const normalizeSearchResults = (relations, { mainFieldName }) => {
 | 
			
		||||
  return {
 | 
			
		||||
    ...relations,
 | 
			
		||||
    data: {
 | 
			
		||||
      pages: [...(relations?.data?.pages ?? [])]?.map((page) =>
 | 
			
		||||
        page?.results.map((relation) => normalizeRelation(relation, { mainFieldName }))
 | 
			
		||||
      ),
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
@ -6,8 +6,8 @@ const FIXTURE_RELATIONS = {
 | 
			
		||||
      {
 | 
			
		||||
        results: [
 | 
			
		||||
          {
 | 
			
		||||
            id: 1,
 | 
			
		||||
            name: 'Relation 1',
 | 
			
		||||
            id: 3,
 | 
			
		||||
            name: 'Relation 3',
 | 
			
		||||
            publishedAt: '2022-08-24T09:29:11.38',
 | 
			
		||||
          },
 | 
			
		||||
 | 
			
		||||
@ -18,8 +18,8 @@ const FIXTURE_RELATIONS = {
 | 
			
		||||
          },
 | 
			
		||||
 | 
			
		||||
          {
 | 
			
		||||
            id: 3,
 | 
			
		||||
            name: 'Relation 3',
 | 
			
		||||
            id: 1,
 | 
			
		||||
            name: 'Relation 1',
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
@ -27,8 +27,8 @@ const FIXTURE_RELATIONS = {
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
describe('normalizeRelations', () => {
 | 
			
		||||
  test('filters out deleted releations', () => {
 | 
			
		||||
describe('RelationInputDataManager || normalizeRelations', () => {
 | 
			
		||||
  test('filters out deleted relations', () => {
 | 
			
		||||
    expect(
 | 
			
		||||
      normalizeRelations(FIXTURE_RELATIONS, {
 | 
			
		||||
        modifiedData: { disconnect: [{ id: 1 }] },
 | 
			
		||||
@ -37,8 +37,8 @@ describe('normalizeRelations', () => {
 | 
			
		||||
      data: {
 | 
			
		||||
        pages: [
 | 
			
		||||
          [
 | 
			
		||||
            expect.objectContaining(FIXTURE_RELATIONS.data.pages[0].results[0]),
 | 
			
		||||
            expect.objectContaining(FIXTURE_RELATIONS.data.pages[0].results[1]),
 | 
			
		||||
            expect.objectContaining(FIXTURE_RELATIONS.data.pages[0].results[2]),
 | 
			
		||||
          ],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
@ -85,9 +85,9 @@ describe('normalizeRelations', () => {
 | 
			
		||||
      data: {
 | 
			
		||||
        pages: [
 | 
			
		||||
          [
 | 
			
		||||
            expect.objectContaining({ href: '/content-manager/collectionType/something/1' }),
 | 
			
		||||
            expect.objectContaining({ href: '/content-manager/collectionType/something/2' }),
 | 
			
		||||
            expect.objectContaining({ href: '/content-manager/collectionType/something/3' }),
 | 
			
		||||
            expect.objectContaining({ href: '/content-manager/collectionType/something/2' }),
 | 
			
		||||
            expect.objectContaining({ href: '/content-manager/collectionType/something/1' }),
 | 
			
		||||
          ],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
@ -137,7 +137,7 @@ describe('normalizeRelations', () => {
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('allows to connect new relations, eventhough pages is empty', () => {
 | 
			
		||||
  test('allows to connect new relations, even though pages is empty', () => {
 | 
			
		||||
    expect(
 | 
			
		||||
      normalizeRelations(
 | 
			
		||||
        {
 | 
			
		||||
@ -161,4 +161,59 @@ describe('normalizeRelations', () => {
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('reverse order of relations pages', () => {
 | 
			
		||||
    const fixtureExtended = {
 | 
			
		||||
      pages: [
 | 
			
		||||
        ...FIXTURE_RELATIONS.data.pages,
 | 
			
		||||
        {
 | 
			
		||||
          results: [
 | 
			
		||||
            {
 | 
			
		||||
              id: 6,
 | 
			
		||||
              name: 'Relation 6',
 | 
			
		||||
              publishedAt: '2022-08-24T09:29:11.38',
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            {
 | 
			
		||||
              id: 5,
 | 
			
		||||
              name: 'Relation 5',
 | 
			
		||||
              publishedAt: '',
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            {
 | 
			
		||||
              id: 4,
 | 
			
		||||
              name: 'Relation 4',
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    expect(
 | 
			
		||||
      normalizeRelations(
 | 
			
		||||
        {
 | 
			
		||||
          data: fixtureExtended,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          modifiedData: { connect: [{ id: 6 }] },
 | 
			
		||||
        }
 | 
			
		||||
      )
 | 
			
		||||
    ).toStrictEqual({
 | 
			
		||||
      data: {
 | 
			
		||||
        pages: [
 | 
			
		||||
          [
 | 
			
		||||
            expect.objectContaining({ id: 6 }),
 | 
			
		||||
            expect.objectContaining({ id: 5 }),
 | 
			
		||||
            expect.objectContaining({ id: 4 }),
 | 
			
		||||
          ],
 | 
			
		||||
          [
 | 
			
		||||
            expect.objectContaining({ id: 3 }),
 | 
			
		||||
            expect.objectContaining({ id: 2 }),
 | 
			
		||||
            expect.objectContaining({ id: 1 }),
 | 
			
		||||
          ],
 | 
			
		||||
          [expect.objectContaining({ id: 6 })],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,68 @@
 | 
			
		||||
import { normalizeSearchResults } from '../normalizeSearchResults';
 | 
			
		||||
 | 
			
		||||
const FIXTURE_RELATIONS = {
 | 
			
		||||
  data: {
 | 
			
		||||
    pages: [
 | 
			
		||||
      {
 | 
			
		||||
        results: [
 | 
			
		||||
          {
 | 
			
		||||
            id: 3,
 | 
			
		||||
            name: 'Relation 3',
 | 
			
		||||
            publishedAt: '2022-08-24T09:29:11.38',
 | 
			
		||||
          },
 | 
			
		||||
 | 
			
		||||
          {
 | 
			
		||||
            id: 2,
 | 
			
		||||
            name: 'Relation 2',
 | 
			
		||||
            publishedAt: '',
 | 
			
		||||
          },
 | 
			
		||||
 | 
			
		||||
          {
 | 
			
		||||
            id: 1,
 | 
			
		||||
            name: 'Relation 1',
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
describe('RelationInputDataManager || normalizeSearchResults', () => {
 | 
			
		||||
  test('add publicationState attribute to each relation', () => {
 | 
			
		||||
    expect(normalizeSearchResults(FIXTURE_RELATIONS, {})).toStrictEqual({
 | 
			
		||||
      data: {
 | 
			
		||||
        pages: [
 | 
			
		||||
          [
 | 
			
		||||
            expect.objectContaining({ publicationState: 'published' }),
 | 
			
		||||
            expect.objectContaining({ publicationState: 'draft' }),
 | 
			
		||||
            expect.objectContaining({ publicationState: false }),
 | 
			
		||||
          ],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('add mainField attribute to each relation', () => {
 | 
			
		||||
    expect(
 | 
			
		||||
      normalizeSearchResults(FIXTURE_RELATIONS, {
 | 
			
		||||
        mainFieldName: 'name',
 | 
			
		||||
      })
 | 
			
		||||
    ).toStrictEqual({
 | 
			
		||||
      data: {
 | 
			
		||||
        pages: [
 | 
			
		||||
          [
 | 
			
		||||
            expect.objectContaining({
 | 
			
		||||
              mainField: FIXTURE_RELATIONS.data.pages[0].results[0].name,
 | 
			
		||||
            }),
 | 
			
		||||
            expect.objectContaining({
 | 
			
		||||
              mainField: FIXTURE_RELATIONS.data.pages[0].results[1].name,
 | 
			
		||||
            }),
 | 
			
		||||
            expect.objectContaining({
 | 
			
		||||
              mainField: FIXTURE_RELATIONS.data.pages[0].results[2].name,
 | 
			
		||||
            }),
 | 
			
		||||
          ],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
@ -8,9 +8,15 @@ import { useRelation } from '../useRelation';
 | 
			
		||||
jest.mock('../../../../core/utils', () => ({
 | 
			
		||||
  ...jest.requireActual('../../../../core/utils'),
 | 
			
		||||
  axiosInstance: {
 | 
			
		||||
    get: jest
 | 
			
		||||
      .fn()
 | 
			
		||||
      .mockResolvedValue({ data: { values: [], pagination: { page: 1, pageCount: 10 } } }),
 | 
			
		||||
    get: jest.fn().mockResolvedValue({
 | 
			
		||||
      data: {
 | 
			
		||||
        results: [
 | 
			
		||||
          { id: 2, name: 'newest', publishedAt: null },
 | 
			
		||||
          { id: 1, name: 'oldest', publishedAt: null },
 | 
			
		||||
        ],
 | 
			
		||||
        pagination: { page: 1, pageCount: 10 },
 | 
			
		||||
      },
 | 
			
		||||
    }),
 | 
			
		||||
  },
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
@ -95,7 +101,7 @@ describe('useRelation', () => {
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('doesn not fetch relations if it was not enabled', async () => {
 | 
			
		||||
  test('does not fetch relations if it was not enabled', async () => {
 | 
			
		||||
    await setup(undefined, { relation: { enabled: false } });
 | 
			
		||||
 | 
			
		||||
    expect(axiosInstance.get).not.toBeCalled();
 | 
			
		||||
@ -119,7 +125,7 @@ describe('useRelation', () => {
 | 
			
		||||
  test('fetch relations next page, if there is one', async () => {
 | 
			
		||||
    axiosInstance.get = jest.fn().mockResolvedValue({
 | 
			
		||||
      data: {
 | 
			
		||||
        values: [],
 | 
			
		||||
        results: [],
 | 
			
		||||
        pagination: {
 | 
			
		||||
          page: 1,
 | 
			
		||||
          pageCount: 3,
 | 
			
		||||
@ -155,7 +161,7 @@ describe('useRelation', () => {
 | 
			
		||||
  test("does not fetch relations next page, if there isn't one", async () => {
 | 
			
		||||
    axiosInstance.get = jest.fn().mockResolvedValue({
 | 
			
		||||
      data: {
 | 
			
		||||
        values: [],
 | 
			
		||||
        results: [],
 | 
			
		||||
        pagination: {
 | 
			
		||||
          page: 1,
 | 
			
		||||
          pageCount: 1,
 | 
			
		||||
@ -191,7 +197,7 @@ describe('useRelation', () => {
 | 
			
		||||
 | 
			
		||||
    const spy = jest
 | 
			
		||||
      .fn()
 | 
			
		||||
      .mockResolvedValue({ data: { values: [], pagination: { page: 1, pageCount: 2 } } });
 | 
			
		||||
      .mockResolvedValue({ data: { results: [], pagination: { page: 1, pageCount: 2 } } });
 | 
			
		||||
    axiosInstance.get = spy;
 | 
			
		||||
 | 
			
		||||
    act(() => {
 | 
			
		||||
@ -237,7 +243,7 @@ describe('useRelation', () => {
 | 
			
		||||
 | 
			
		||||
    const spy = jest
 | 
			
		||||
      .fn()
 | 
			
		||||
      .mockResolvedValue({ data: { values: [], pagination: { page: 1, pageCount: 2 } } });
 | 
			
		||||
      .mockResolvedValue({ data: { results: [], pagination: { page: 1, pageCount: 2 } } });
 | 
			
		||||
    axiosInstance.get = spy;
 | 
			
		||||
 | 
			
		||||
    act(() => {
 | 
			
		||||
@ -269,12 +275,12 @@ describe('useRelation', () => {
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test("doesn not fetch search next page, if there isn't one", async () => {
 | 
			
		||||
  test("does not fetch search next page, if there isn't one", async () => {
 | 
			
		||||
    const { result, waitForNextUpdate } = await setup(undefined);
 | 
			
		||||
 | 
			
		||||
    const spy = jest
 | 
			
		||||
      .fn()
 | 
			
		||||
      .mockResolvedValue({ data: { values: [], pagination: { page: 1, pageCount: 1 } } });
 | 
			
		||||
    const spy = jest.fn().mockResolvedValue({
 | 
			
		||||
      data: { results: [], pagination: { page: 1, pageCount: 1 } },
 | 
			
		||||
    });
 | 
			
		||||
    axiosInstance.get = spy;
 | 
			
		||||
 | 
			
		||||
    act(() => {
 | 
			
		||||
 | 
			
		||||
@ -22,15 +22,19 @@ export const useRelation = (cacheKey, { relation, search }) => {
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const fetchSearch = async ({ pageParam = 1 }) => {
 | 
			
		||||
    const { data } = await axiosInstance.get(search.endpoint, {
 | 
			
		||||
      params: {
 | 
			
		||||
        ...(search.pageParams ?? {}),
 | 
			
		||||
        ...searchParams,
 | 
			
		||||
        page: pageParam,
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
    try {
 | 
			
		||||
      const { data } = await axiosInstance.get(search.endpoint, {
 | 
			
		||||
        params: {
 | 
			
		||||
          ...(search.pageParams ?? {}),
 | 
			
		||||
          ...searchParams,
 | 
			
		||||
          page: pageParam,
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    return data;
 | 
			
		||||
      return data;
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const relationsRes = useInfiniteQuery(['relation', cacheKey], fetchRelations, {
 | 
			
		||||
@ -44,6 +48,9 @@ export const useRelation = (cacheKey, { relation, search }) => {
 | 
			
		||||
      // eslint-disable-next-line consistent-return
 | 
			
		||||
      return lastPage.pagination.page + 1;
 | 
			
		||||
    },
 | 
			
		||||
    select: (data) => ({
 | 
			
		||||
      pages: data.pages.map((page) => ({ ...page, results: [...(page.results ?? [])].reverse() })),
 | 
			
		||||
    }),
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const searchRes = useInfiniteQuery(
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user