mirror of
https://github.com/strapi/strapi.git
synced 2025-09-12 18:19:47 +00:00
Merge pull request #21428 from strapi/fix/cm-relations
fix: cm relations
This commit is contained in:
commit
9a4af3a3cc
@ -120,6 +120,7 @@ const EditViewPage = () => {
|
||||
|
||||
return transformDocument(schema, components)(form);
|
||||
}, [document, isCreatingDocument, isSingleType, schema, components]);
|
||||
|
||||
if (hasError) {
|
||||
return <Page.Error />;
|
||||
}
|
||||
|
@ -19,9 +19,10 @@ import {
|
||||
ButtonProps,
|
||||
} from '@strapi/design-system';
|
||||
import { Cross, More, WarningCircle } from '@strapi/icons';
|
||||
import mapValues from 'lodash/fp/mapValues';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useMatch, useNavigate } from 'react-router-dom';
|
||||
import { styled, DefaultTheme } from 'styled-components';
|
||||
import { DefaultTheme } from 'styled-components';
|
||||
|
||||
import { PUBLISHED_AT_ATTRIBUTE_NAME } from '../../../constants/attributes';
|
||||
import { SINGLE_TYPES } from '../../../constants/collections';
|
||||
@ -35,6 +36,7 @@ import { getTranslation } from '../../../utils/translations';
|
||||
|
||||
import type { RelationsFormValue } from './FormInputs/Relations';
|
||||
import type { DocumentActionComponent } from '../../../content-manager';
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Types
|
||||
* -----------------------------------------------------------------------------------------------*/
|
||||
@ -493,6 +495,22 @@ const DocumentActionModal = ({
|
||||
);
|
||||
};
|
||||
|
||||
const transformData = (data: Record<string, any>): any => {
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(transformData);
|
||||
}
|
||||
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
if ('apiData' in data) {
|
||||
return data.apiData;
|
||||
}
|
||||
|
||||
return mapValues(transformData)(data);
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* DocumentActionComponents
|
||||
* -----------------------------------------------------------------------------------------------*/
|
||||
@ -643,7 +661,7 @@ const PublishAction: DocumentActionComponent = ({
|
||||
documentId,
|
||||
params,
|
||||
},
|
||||
formValues
|
||||
transformData(formValues)
|
||||
);
|
||||
|
||||
if ('data' in res && collectionType !== SINGLE_TYPES) {
|
||||
@ -797,7 +815,7 @@ const UpdateAction: DocumentActionComponent = ({
|
||||
documentId: cloneMatch.params.origin!,
|
||||
params,
|
||||
},
|
||||
document
|
||||
transformData(document)
|
||||
);
|
||||
|
||||
if ('data' in res) {
|
||||
@ -823,7 +841,7 @@ const UpdateAction: DocumentActionComponent = ({
|
||||
documentId,
|
||||
params,
|
||||
},
|
||||
document
|
||||
transformData(document)
|
||||
);
|
||||
|
||||
if (
|
||||
@ -841,7 +859,7 @@ const UpdateAction: DocumentActionComponent = ({
|
||||
model,
|
||||
params,
|
||||
},
|
||||
document
|
||||
transformData(document)
|
||||
);
|
||||
|
||||
if ('data' in res && collectionType !== SINGLE_TYPES) {
|
||||
|
@ -84,7 +84,13 @@ function useHandleDisconnect(fieldName: string, consumerName: string) {
|
||||
}
|
||||
}
|
||||
|
||||
addFieldRow(`${fieldName}.disconnect`, { id: relation.id });
|
||||
addFieldRow(`${fieldName}.disconnect`, {
|
||||
id: relation.id,
|
||||
apiData: {
|
||||
documentId: relation.documentId,
|
||||
locale: relation.locale,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return handleDisconnect;
|
||||
@ -145,14 +151,23 @@ const RelationsField = React.forwardRef<HTMLDivElement, RelationsFieldProps>(
|
||||
const isMorph = props.attribute.relation.toLowerCase().includes('morph');
|
||||
const isDisabled = isMorph || disabled;
|
||||
|
||||
const { id: componentId, uid } = useComponent('RelationsField', ({ uid, id }) => ({ id, uid }));
|
||||
const { componentId, componentUID } = useComponent('RelationsField', ({ uid, id }) => ({
|
||||
componentId: id,
|
||||
componentUID: uid,
|
||||
}));
|
||||
|
||||
const isSubmitting = useForm('RelationsList', (state) => state.isSubmitting);
|
||||
|
||||
React.useEffect(() => {
|
||||
setCurrentPage(1);
|
||||
}, [isSubmitting]);
|
||||
|
||||
/**
|
||||
* We'll always have a documentId in a created entry, so we look for a componentId first.
|
||||
* Same with `uid` and `documentModel`.
|
||||
*/
|
||||
const id = componentId ? componentId.toString() : documentId;
|
||||
const model = uid ?? documentModel;
|
||||
const model = componentUID ?? documentModel;
|
||||
|
||||
/**
|
||||
* The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
|
||||
@ -199,6 +214,7 @@ const RelationsField = React.forwardRef<HTMLDivElement, RelationsFieldProps>(
|
||||
|
||||
const realServerRelationsCount =
|
||||
'pagination' in data && data.pagination ? data.pagination.total : 0;
|
||||
|
||||
/**
|
||||
* Items that are already connected, but reordered would be in
|
||||
* this list, so to get an accurate figure, we remove them.
|
||||
@ -259,6 +275,10 @@ const RelationsField = React.forwardRef<HTMLDivElement, RelationsFieldProps>(
|
||||
|
||||
const item = {
|
||||
id: relation.id,
|
||||
apiData: {
|
||||
documentId: relation.documentId,
|
||||
locale: relation.locale,
|
||||
},
|
||||
status: relation.status,
|
||||
/**
|
||||
* If there's a last item, that's the first key we use to generate out next one.
|
||||
@ -268,7 +288,7 @@ const RelationsField = React.forwardRef<HTMLDivElement, RelationsFieldProps>(
|
||||
[props.mainField?.name ?? 'documentId']: relation[props.mainField?.name ?? 'documentId'],
|
||||
label: getRelationLabel(relation, props.mainField),
|
||||
// @ts-expect-error – targetModel does exist on the attribute, but it's not typed.
|
||||
href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}/${relation.documentId}`,
|
||||
href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`,
|
||||
};
|
||||
|
||||
if (ONE_WAY_RELATIONS.includes(props.attribute.relation)) {
|
||||
@ -294,7 +314,8 @@ const RelationsField = React.forwardRef<HTMLDivElement, RelationsFieldProps>(
|
||||
<StyledFlex direction="column" alignItems="start" gap={2} width="100%">
|
||||
<RelationsInput
|
||||
disabled={isDisabled}
|
||||
id={id}
|
||||
// NOTE: we should not default to using the documentId if the component is being created (componentUID is undefined)
|
||||
id={componentUID ? (componentId ? `${componentId}` : '') : documentId}
|
||||
label={`${label} ${relationsCount > 0 ? `(${relationsCount})` : ''}`}
|
||||
model={model}
|
||||
onChange={handleConnect}
|
||||
@ -389,7 +410,7 @@ const addLabelAndHref =
|
||||
// Fallback to `id` if there is no `mainField` value, which will overwrite the above `documentId` property with the exact same data.
|
||||
[mainField?.name ?? 'documentId']: relation[mainField?.name ?? 'documentId'],
|
||||
label: getRelationLabel(relation, mainField),
|
||||
href: `${href}/${relation.documentId}`,
|
||||
href: `${href}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`,
|
||||
};
|
||||
});
|
||||
|
||||
@ -454,6 +475,7 @@ const RelationsInput = ({
|
||||
* individual components. Therefore we split the string and take the last item.
|
||||
*/
|
||||
const [targetField] = name.split('.').slice(-1);
|
||||
|
||||
searchForTrigger({
|
||||
model,
|
||||
targetField,
|
||||
@ -701,9 +723,7 @@ const RelationsList = ({
|
||||
*/
|
||||
const connectedRelations = newData
|
||||
.reduce<Relation[]>((acc, relation, currentIndex, array) => {
|
||||
const relationOnServer = serverData.find(
|
||||
(oldRelation) => oldRelation.documentId === relation.documentId
|
||||
);
|
||||
const relationOnServer = serverData.find((oldRelation) => oldRelation.id === relation.id);
|
||||
|
||||
const relationInFront = array[currentIndex + 1];
|
||||
|
||||
@ -712,11 +732,23 @@ const RelationsList = ({
|
||||
? {
|
||||
before: relationInFront.documentId,
|
||||
locale: relationInFront.locale,
|
||||
status: relationInFront.status,
|
||||
status:
|
||||
'publishedAt' in relationInFront && relationInFront.publishedAt
|
||||
? 'published'
|
||||
: 'draft',
|
||||
}
|
||||
: { end: true };
|
||||
|
||||
const relationWithPosition: Relation = { ...relation, position };
|
||||
const relationWithPosition: Relation = {
|
||||
...relation,
|
||||
...{
|
||||
apiData: {
|
||||
documentId: relation.documentId,
|
||||
locale: relation.locale,
|
||||
position,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return [...acc, relationWithPosition];
|
||||
}
|
||||
@ -899,7 +931,7 @@ const ListItem = ({ data, index, style }: ListItemProps) => {
|
||||
} = data;
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const { href, documentId, label, status } = relations[index];
|
||||
const { href, id, label, status } = relations[index];
|
||||
|
||||
const [{ handlerId, isDragging, handleKeyDown }, relationRef, dropRef, dragRef, dragPreviewRef] =
|
||||
useDragAndDrop<number, Omit<RelationDragPreviewProps, 'width'>, HTMLDivElement>(
|
||||
@ -910,7 +942,7 @@ const ListItem = ({ data, index, style }: ListItemProps) => {
|
||||
item: {
|
||||
displayedValue: label,
|
||||
status,
|
||||
id: documentId,
|
||||
id: id,
|
||||
index,
|
||||
},
|
||||
onMoveItem: handleMoveItem,
|
||||
|
@ -67,11 +67,8 @@ const relationsApi = contentManagerApi.injectEndpoints({
|
||||
* Relations will always have unique IDs, so we can therefore assume
|
||||
* that we only need to push the new items to the cache.
|
||||
*/
|
||||
const existingIds = currentCache.results.map((item) => item.documentId);
|
||||
const uniqueNewItems = newItems.results.filter(
|
||||
(item) => !existingIds.includes(item.documentId)
|
||||
);
|
||||
currentCache.results.push(...prepareTempKeys(uniqueNewItems, currentCache.results));
|
||||
|
||||
currentCache.results.push(...prepareTempKeys(newItems.results, currentCache.results));
|
||||
currentCache.pagination = newItems.pagination;
|
||||
} else if (newItems.pagination.page === 1) {
|
||||
/**
|
||||
|
@ -49,17 +49,39 @@ const sanitizeMainField = (model: any, mainField: any, userAbility: any) => {
|
||||
return mainField;
|
||||
};
|
||||
|
||||
const addStatusToRelations = async (uid: UID.ContentType, relations: RelationEntity[]) => {
|
||||
if (!contentTypes.hasDraftAndPublish(strapi.contentTypes[uid])) {
|
||||
/**
|
||||
*
|
||||
* All relations sent to this function should have the same status or no status
|
||||
*/
|
||||
const addStatusToRelations = async (targetUid: UID.Schema, relations: RelationEntity[]) => {
|
||||
if (!contentTypes.hasDraftAndPublish(strapi.getModel(targetUid))) {
|
||||
return relations;
|
||||
}
|
||||
|
||||
const documentMetadata = getService('document-metadata');
|
||||
const documentsAvailableStatus = await documentMetadata.getManyAvailableStatus(uid, relations);
|
||||
|
||||
if (!relations.length) {
|
||||
return relations;
|
||||
}
|
||||
|
||||
const firstRelation = relations[0];
|
||||
|
||||
const filters: any = {
|
||||
documentId: { $in: relations.map((r) => r.documentId) },
|
||||
// NOTE: find the "opposite" status
|
||||
publishedAt: firstRelation.publishedAt !== null ? { $null: true } : { $notNull: true },
|
||||
};
|
||||
|
||||
const availableStatus = await strapi.query(targetUid).findMany({
|
||||
select: ['id', 'documentId', 'locale', 'updatedAt', 'createdAt', 'publishedAt'],
|
||||
filters,
|
||||
});
|
||||
|
||||
return relations.map((relation: RelationEntity) => {
|
||||
const availableStatuses = documentsAvailableStatus.filter(
|
||||
(availableDocument: RelationEntity) => availableDocument.documentId === relation.documentId
|
||||
const availableStatuses = availableStatus.filter(
|
||||
(availableDocument: RelationEntity) =>
|
||||
availableDocument.documentId === relation.documentId &&
|
||||
(relation.locale ? availableDocument.locale === relation.locale : true)
|
||||
);
|
||||
|
||||
return {
|
||||
@ -396,14 +418,14 @@ export default {
|
||||
attribute,
|
||||
targetField,
|
||||
fieldsToSelect,
|
||||
source: {
|
||||
schema: { uid: sourceUid },
|
||||
},
|
||||
target: {
|
||||
schema: { uid: targetUid },
|
||||
},
|
||||
status,
|
||||
source: { schema: sourceSchema },
|
||||
target: { schema: targetSchema },
|
||||
} = await this.extractAndValidateRequestInfo(ctx, id);
|
||||
|
||||
const { uid: sourceUid } = sourceSchema;
|
||||
const { uid: targetUid } = targetSchema;
|
||||
|
||||
const permissionQuery = await getService('permission-checker')
|
||||
.create({ userAbility, model: targetUid })
|
||||
.sanitizedQuery.read({ fields: fieldsToSelect });
|
||||
@ -424,6 +446,23 @@ export default {
|
||||
// Ensure response is an array
|
||||
.then((res) => ({ results: res ? [res] : [] }));
|
||||
|
||||
const filters: {
|
||||
publishedAt?: Record<string, any>;
|
||||
} = {};
|
||||
|
||||
if (sourceSchema?.options?.draftAndPublish) {
|
||||
if (targetSchema?.options?.draftAndPublish) {
|
||||
if (status === 'published') {
|
||||
filters.publishedAt = { $notNull: true };
|
||||
} else {
|
||||
filters.publishedAt = { $null: true };
|
||||
}
|
||||
}
|
||||
} else if (targetSchema?.options?.draftAndPublish) {
|
||||
// NOTE: we must return the drafts as some targets might not have a published version yet
|
||||
filters.publishedAt = { $null: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* If user does not have access to specific relations (custom conditions),
|
||||
* only the ids of the relations are returned.
|
||||
@ -434,10 +473,11 @@ export default {
|
||||
* The response contains the union of the two queries.
|
||||
*/
|
||||
const res = await loadRelations({ id: entryId }, targetField, {
|
||||
select: ['id', 'documentId', 'locale', 'publishedAt'],
|
||||
select: ['id', 'documentId', 'locale', 'publishedAt', 'updatedAt'],
|
||||
ordering: 'desc',
|
||||
page: ctx.request.query.page,
|
||||
pageSize: ctx.request.query.pageSize,
|
||||
filters,
|
||||
});
|
||||
|
||||
/**
|
||||
@ -458,6 +498,7 @@ export default {
|
||||
ordering: 'desc',
|
||||
});
|
||||
|
||||
// NOTE: the order is very import to make sure sanitized relations are kept in priority
|
||||
const relationsUnion = uniqBy('id', concat(sanitizedRes.results, res.results));
|
||||
|
||||
ctx.body = {
|
||||
|
@ -7,11 +7,11 @@ import type { DocumentMetadata } from '../../../shared/contracts/collection-type
|
||||
import { getValidatableFieldsPopulate } from './utils/populate';
|
||||
|
||||
export interface DocumentVersion {
|
||||
id: number;
|
||||
id: string | number;
|
||||
documentId: Modules.Documents.ID;
|
||||
locale: string;
|
||||
updatedAt: string | null | Date;
|
||||
publishedAt: string | null | Date;
|
||||
locale?: string;
|
||||
updatedAt?: string | null | Date;
|
||||
publishedAt?: string | null | Date;
|
||||
}
|
||||
|
||||
const AVAILABLE_STATUS_FIELDS = [
|
||||
@ -86,7 +86,9 @@ export default ({ strapi }: { strapi: Core.Strapi }) => ({
|
||||
const versionsByLocale = groupBy('locale', allVersions);
|
||||
|
||||
// Delete the current locale
|
||||
if (version.locale) {
|
||||
delete versionsByLocale[version.locale];
|
||||
}
|
||||
|
||||
// For each locale, get the ones with the same status
|
||||
// There will not be a draft and a version counterpart if the content
|
||||
|
@ -1,8 +1,11 @@
|
||||
import '@strapi/types';
|
||||
|
||||
import { DocumentManagerService } from 'src/services/document-manager';
|
||||
import DocumentMetadata from 'src/services/document-metadata';
|
||||
|
||||
type Services = {
|
||||
'document-manager': DocumentManagerService;
|
||||
'document-metadata': typeof DocumentMetadata;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
|
@ -291,7 +291,10 @@ export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
|
||||
]);
|
||||
|
||||
// Load any unidirectional relation targetting the old published entries
|
||||
const relationsToSync = await unidirectionalRelations.load(uid, oldPublishedVersions);
|
||||
const relationsToSync = await unidirectionalRelations.load(uid, {
|
||||
newVersions: draftsToPublish,
|
||||
oldVersions: oldPublishedVersions,
|
||||
});
|
||||
|
||||
// Delete old published versions
|
||||
await async.map(oldPublishedVersions, (entry: any) => entries.delete(entry.id));
|
||||
@ -302,7 +305,11 @@ export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
|
||||
);
|
||||
|
||||
// Sync unidirectional relations with the new published entries
|
||||
await unidirectionalRelations.sync(oldPublishedVersions, publishedEntries, relationsToSync);
|
||||
await unidirectionalRelations.sync(
|
||||
[...oldPublishedVersions, ...draftsToPublish],
|
||||
publishedEntries,
|
||||
relationsToSync
|
||||
);
|
||||
|
||||
publishedEntries.forEach(emitEvent('entry.publish'));
|
||||
|
||||
@ -358,7 +365,10 @@ export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
|
||||
]);
|
||||
|
||||
// Load any unidirectional relation targeting the old drafts
|
||||
const relationsToSync = await unidirectionalRelations.load(uid, oldDrafts);
|
||||
const relationsToSync = await unidirectionalRelations.load(uid, {
|
||||
newVersions: versionsToDraft,
|
||||
oldVersions: oldDrafts,
|
||||
});
|
||||
|
||||
// Delete old drafts
|
||||
await async.map(oldDrafts, (entry: any) => entries.delete(entry.id));
|
||||
@ -369,7 +379,11 @@ export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
|
||||
);
|
||||
|
||||
// Sync unidirectional relations with the new draft entries
|
||||
await unidirectionalRelations.sync(oldDrafts, draftEntries, relationsToSync);
|
||||
await unidirectionalRelations.sync(
|
||||
[...oldDrafts, ...versionsToDraft],
|
||||
draftEntries,
|
||||
relationsToSync
|
||||
);
|
||||
|
||||
draftEntries.forEach(emitEvent('entry.draft-discard'));
|
||||
return { documentId, entries: draftEntries };
|
||||
|
@ -1,18 +1,19 @@
|
||||
/* eslint-disable no-continue */
|
||||
import { keyBy } from 'lodash/fp';
|
||||
import { keyBy, omit } from 'lodash/fp';
|
||||
|
||||
import { UID, Schema } from '@strapi/types';
|
||||
|
||||
interface LoadContext {
|
||||
oldVersions: { id: string; locale: string }[];
|
||||
newVersions: { id: string; locale: string }[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads lingering relations that need to be updated when overriding a published or draft entry.
|
||||
* This is necessary because the relations are uni-directional and the target entry is not aware of the source entry.
|
||||
* This is not the case for bi-directional relations, where the target entry is also linked to the source entry.
|
||||
*
|
||||
* @param uid The content type uid
|
||||
* @param oldEntries The old entries that are being overridden
|
||||
* @returns An array of relations that need to be updated with the join table reference.
|
||||
*/
|
||||
const load = async (uid: UID.ContentType, oldEntries: { id: string; locale: string }[]) => {
|
||||
const load = async (uid: UID.ContentType, { oldVersions, newVersions }: LoadContext) => {
|
||||
const updates = [] as any;
|
||||
|
||||
// Iterate all components and content types to find relations that need to be updated
|
||||
@ -27,29 +28,80 @@ const load = async (uid: UID.ContentType, oldEntries: { id: string; locale: stri
|
||||
/**
|
||||
* Only consider unidirectional relations
|
||||
*/
|
||||
if (attribute.type !== 'relation') continue;
|
||||
if (attribute.target !== uid) continue;
|
||||
if (attribute.inversedBy || attribute.mappedBy) continue;
|
||||
const joinTable = attribute.joinTable;
|
||||
// TODO: joinColumn relations
|
||||
if (!joinTable) continue;
|
||||
if (
|
||||
attribute.type !== 'relation' ||
|
||||
attribute.target !== uid ||
|
||||
attribute.inversedBy ||
|
||||
attribute.mappedBy
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { name } = joinTable.inverseJoinColumn;
|
||||
// TODO: joinColumn relations
|
||||
const joinTable = attribute.joinTable;
|
||||
if (!joinTable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { name: sourceColumnName } = joinTable.joinColumn;
|
||||
const { name: targetColumnName } = joinTable.inverseJoinColumn;
|
||||
|
||||
/**
|
||||
* Load all relations that need to be updated
|
||||
*/
|
||||
const oldEntriesIds = oldEntries.map((entry) => entry.id);
|
||||
const relations = await strapi.db
|
||||
// NOTE: when the model has draft and publish, we can assume relation are only draft to draft & published to published
|
||||
const ids = oldVersions.map((entry) => entry.id);
|
||||
|
||||
const oldVersionsRelations = await strapi.db
|
||||
.getConnection()
|
||||
.select('*')
|
||||
.from(joinTable.name)
|
||||
.whereIn(name, oldEntriesIds)
|
||||
.whereIn(targetColumnName, ids)
|
||||
.transacting(trx);
|
||||
|
||||
if (relations.length === 0) continue;
|
||||
if (oldVersionsRelations.length > 0) {
|
||||
updates.push({ joinTable, relations: oldVersionsRelations });
|
||||
}
|
||||
|
||||
updates.push({ joinTable, relations });
|
||||
/**
|
||||
* if publishing
|
||||
* if published version exists
|
||||
* updated published versions links
|
||||
* else
|
||||
* create link to newly published version
|
||||
*
|
||||
* if discarding
|
||||
* if published version link exists & not draft version link
|
||||
* create link to new draft version
|
||||
*/
|
||||
|
||||
if (!model.options?.draftAndPublish) {
|
||||
const ids = newVersions.map((entry) => entry.id);
|
||||
|
||||
const newVersionsRelations = await strapi.db
|
||||
.getConnection()
|
||||
.select('*')
|
||||
.from(joinTable.name)
|
||||
.whereIn(targetColumnName, ids)
|
||||
.transacting(trx);
|
||||
|
||||
if (newVersionsRelations.length > 0) {
|
||||
// when publishing a draft that doesn't have a published version yet,
|
||||
// copy the links to the draft over to the published version
|
||||
// when discarding a published version, if no drafts exists
|
||||
const discardToAdd = newVersionsRelations
|
||||
.filter((relation) => {
|
||||
const matchingOldVerion = oldVersionsRelations.find((oldRelation) => {
|
||||
return oldRelation[sourceColumnName] === relation[sourceColumnName];
|
||||
});
|
||||
|
||||
return !matchingOldVerion;
|
||||
})
|
||||
.map(omit('id'));
|
||||
|
||||
updates.push({ joinTable, relations: discardToAdd });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -89,8 +141,9 @@ const sync = async (
|
||||
// Iterate old relations that are deleted and insert the new ones
|
||||
for (const { joinTable, relations } of oldRelations) {
|
||||
// Update old ids with the new ones
|
||||
const newRelations = relations.map((relation) => {
|
||||
const column = joinTable.inverseJoinColumn.name;
|
||||
|
||||
const newRelations = relations.map((relation) => {
|
||||
const newId = oldEntriesMap[relation[column]];
|
||||
return { ...relation, [column]: newId };
|
||||
});
|
||||
|
@ -138,7 +138,7 @@ describe('Relation permissions', () => {
|
||||
|
||||
const shopEntry = await createEntry(
|
||||
'api::shop.shop',
|
||||
{ name: 'Shop', products: [product.id] },
|
||||
{ name: 'Shop', products: [product.documentId] },
|
||||
populateShop
|
||||
);
|
||||
shop = shopEntry.data;
|
||||
|
Loading…
x
Reference in New Issue
Block a user