mirror of
https://github.com/strapi/strapi.git
synced 2025-08-03 22:39:01 +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 { RelationInput } from '../RelationInput';
|
||||||
import { useRelation } from '../../hooks/useRelation';
|
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 { PUBLICATION_STATES, RELATIONS_TO_DISPLAY, SEARCH_RESULTS_TO_DISPLAY } from './constants';
|
||||||
import { getTrad } from '../../utils';
|
import { getTrad } from '../../utils';
|
||||||
|
|
||||||
@ -194,9 +194,8 @@ export const RelationInputDataManager = ({
|
|||||||
}}
|
}}
|
||||||
relations={normalizedRelations}
|
relations={normalizedRelations}
|
||||||
required={required}
|
required={required}
|
||||||
searchResults={normalizeRelations(search, {
|
searchResults={normalizeSearchResults(search, {
|
||||||
mainFieldName: mainField.name,
|
mainFieldName: mainField.name,
|
||||||
search: 'search',
|
|
||||||
})}
|
})}
|
||||||
size={size}
|
size={size}
|
||||||
/>
|
/>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
export { default as connect } from './connect';
|
export { default as connect } from './connect';
|
||||||
export { default as select } from './select';
|
export { default as select } from './select';
|
||||||
export { normalizeRelations } from './normalizeRelations';
|
export { normalizeRelations } from './normalizeRelations';
|
||||||
|
export { normalizeSearchResults } from './normalizeSearchResults';
|
||||||
|
@ -2,7 +2,7 @@ import { getRelationLink } from './getRelationLink';
|
|||||||
|
|
||||||
import { PUBLICATION_STATES } from '../constants';
|
import { PUBLICATION_STATES } from '../constants';
|
||||||
|
|
||||||
const normalizeRelation = (relation, { shouldAddLink, mainFieldName, targetModel }) => {
|
export const normalizeRelation = (relation, { shouldAddLink, mainFieldName, targetModel }) => {
|
||||||
const nextRelation = { ...relation };
|
const nextRelation = { ...relation };
|
||||||
|
|
||||||
if (shouldAddLink) {
|
if (shouldAddLink) {
|
||||||
@ -22,6 +22,14 @@ const normalizeRelation = (relation, { shouldAddLink, mainFieldName, targetModel
|
|||||||
return nextRelation;
|
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 = (
|
export const normalizeRelations = (
|
||||||
relations,
|
relations,
|
||||||
{ modifiedData = {}, shouldAddLink = false, mainFieldName, targetModel }
|
{ modifiedData = {}, shouldAddLink = false, mainFieldName, targetModel }
|
||||||
@ -31,7 +39,7 @@ export const normalizeRelations = (
|
|||||||
data: {
|
data: {
|
||||||
pages:
|
pages:
|
||||||
[
|
[
|
||||||
...(relations?.data?.pages ?? []),
|
...(relations?.data?.pages.reverse() ?? []),
|
||||||
...(modifiedData?.connect ? [{ results: modifiedData.connect }] : []),
|
...(modifiedData?.connect ? [{ results: modifiedData.connect }] : []),
|
||||||
]
|
]
|
||||||
?.map((page) =>
|
?.map((page) =>
|
||||||
@ -44,7 +52,6 @@ export const normalizeRelations = (
|
|||||||
)
|
)
|
||||||
.map((relation) =>
|
.map((relation) =>
|
||||||
normalizeRelation(relation, {
|
normalizeRelation(relation, {
|
||||||
modifiedData,
|
|
||||||
shouldAddLink,
|
shouldAddLink,
|
||||||
mainFieldName,
|
mainFieldName,
|
||||||
targetModel,
|
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: [
|
results: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 3,
|
||||||
name: 'Relation 1',
|
name: 'Relation 3',
|
||||||
publishedAt: '2022-08-24T09:29:11.38',
|
publishedAt: '2022-08-24T09:29:11.38',
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -18,8 +18,8 @@ const FIXTURE_RELATIONS = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 1,
|
||||||
name: 'Relation 3',
|
name: 'Relation 1',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -27,8 +27,8 @@ const FIXTURE_RELATIONS = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('normalizeRelations', () => {
|
describe('RelationInputDataManager || normalizeRelations', () => {
|
||||||
test('filters out deleted releations', () => {
|
test('filters out deleted relations', () => {
|
||||||
expect(
|
expect(
|
||||||
normalizeRelations(FIXTURE_RELATIONS, {
|
normalizeRelations(FIXTURE_RELATIONS, {
|
||||||
modifiedData: { disconnect: [{ id: 1 }] },
|
modifiedData: { disconnect: [{ id: 1 }] },
|
||||||
@ -37,8 +37,8 @@ describe('normalizeRelations', () => {
|
|||||||
data: {
|
data: {
|
||||||
pages: [
|
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[1]),
|
||||||
expect.objectContaining(FIXTURE_RELATIONS.data.pages[0].results[2]),
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -85,9 +85,9 @@ describe('normalizeRelations', () => {
|
|||||||
data: {
|
data: {
|
||||||
pages: [
|
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/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(
|
expect(
|
||||||
normalizeRelations(
|
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.mock('../../../../core/utils', () => ({
|
||||||
...jest.requireActual('../../../../core/utils'),
|
...jest.requireActual('../../../../core/utils'),
|
||||||
axiosInstance: {
|
axiosInstance: {
|
||||||
get: jest
|
get: jest.fn().mockResolvedValue({
|
||||||
.fn()
|
data: {
|
||||||
.mockResolvedValue({ data: { values: [], pagination: { page: 1, pageCount: 10 } } }),
|
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 } });
|
await setup(undefined, { relation: { enabled: false } });
|
||||||
|
|
||||||
expect(axiosInstance.get).not.toBeCalled();
|
expect(axiosInstance.get).not.toBeCalled();
|
||||||
@ -119,7 +125,7 @@ describe('useRelation', () => {
|
|||||||
test('fetch relations next page, if there is one', async () => {
|
test('fetch relations next page, if there is one', async () => {
|
||||||
axiosInstance.get = jest.fn().mockResolvedValue({
|
axiosInstance.get = jest.fn().mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
values: [],
|
results: [],
|
||||||
pagination: {
|
pagination: {
|
||||||
page: 1,
|
page: 1,
|
||||||
pageCount: 3,
|
pageCount: 3,
|
||||||
@ -155,7 +161,7 @@ describe('useRelation', () => {
|
|||||||
test("does not fetch relations next page, if there isn't one", async () => {
|
test("does not fetch relations next page, if there isn't one", async () => {
|
||||||
axiosInstance.get = jest.fn().mockResolvedValue({
|
axiosInstance.get = jest.fn().mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
values: [],
|
results: [],
|
||||||
pagination: {
|
pagination: {
|
||||||
page: 1,
|
page: 1,
|
||||||
pageCount: 1,
|
pageCount: 1,
|
||||||
@ -191,7 +197,7 @@ describe('useRelation', () => {
|
|||||||
|
|
||||||
const spy = jest
|
const spy = jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockResolvedValue({ data: { values: [], pagination: { page: 1, pageCount: 2 } } });
|
.mockResolvedValue({ data: { results: [], pagination: { page: 1, pageCount: 2 } } });
|
||||||
axiosInstance.get = spy;
|
axiosInstance.get = spy;
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@ -237,7 +243,7 @@ describe('useRelation', () => {
|
|||||||
|
|
||||||
const spy = jest
|
const spy = jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockResolvedValue({ data: { values: [], pagination: { page: 1, pageCount: 2 } } });
|
.mockResolvedValue({ data: { results: [], pagination: { page: 1, pageCount: 2 } } });
|
||||||
axiosInstance.get = spy;
|
axiosInstance.get = spy;
|
||||||
|
|
||||||
act(() => {
|
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 { result, waitForNextUpdate } = await setup(undefined);
|
||||||
|
|
||||||
const spy = jest
|
const spy = jest.fn().mockResolvedValue({
|
||||||
.fn()
|
data: { results: [], pagination: { page: 1, pageCount: 1 } },
|
||||||
.mockResolvedValue({ data: { values: [], pagination: { page: 1, pageCount: 1 } } });
|
});
|
||||||
axiosInstance.get = spy;
|
axiosInstance.get = spy;
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
|
@ -22,15 +22,19 @@ export const useRelation = (cacheKey, { relation, search }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fetchSearch = async ({ pageParam = 1 }) => {
|
const fetchSearch = async ({ pageParam = 1 }) => {
|
||||||
const { data } = await axiosInstance.get(search.endpoint, {
|
try {
|
||||||
params: {
|
const { data } = await axiosInstance.get(search.endpoint, {
|
||||||
...(search.pageParams ?? {}),
|
params: {
|
||||||
...searchParams,
|
...(search.pageParams ?? {}),
|
||||||
page: pageParam,
|
...searchParams,
|
||||||
},
|
page: pageParam,
|
||||||
});
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
} catch (err) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const relationsRes = useInfiniteQuery(['relation', cacheKey], fetchRelations, {
|
const relationsRes = useInfiniteQuery(['relation', cacheKey], fetchRelations, {
|
||||||
@ -44,6 +48,9 @@ export const useRelation = (cacheKey, { relation, search }) => {
|
|||||||
// eslint-disable-next-line consistent-return
|
// eslint-disable-next-line consistent-return
|
||||||
return lastPage.pagination.page + 1;
|
return lastPage.pagination.page + 1;
|
||||||
},
|
},
|
||||||
|
select: (data) => ({
|
||||||
|
pages: data.pages.map((page) => ({ ...page, results: [...(page.results ?? [])].reverse() })),
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const searchRes = useInfiniteQuery(
|
const searchRes = useInfiniteQuery(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user