mirror of
https://github.com/strapi/strapi.git
synced 2025-12-27 23:24:03 +00:00
fix: cleanData can now check the original location of the relation for correct comparison
This commit is contained in:
parent
8d6a247b14
commit
a9d481673d
@ -21,7 +21,7 @@ import {
|
||||
getAPIInnerErrors,
|
||||
} from '@strapi/helper-plugin';
|
||||
|
||||
import { getTrad, removeKeyInObject } from '../../utils';
|
||||
import { getTrad } from '../../utils';
|
||||
|
||||
import selectCrudReducer from '../../sharedReducers/crudReducer/selectors';
|
||||
|
||||
@ -361,11 +361,9 @@ const EditViewDataManagerProvider = ({
|
||||
|
||||
const createFormData = useCallback(
|
||||
(modifiedData, initialData) => {
|
||||
// First we need to remove the added keys needed for the dnd
|
||||
const preparedData = removeKeyInObject(cloneDeep(modifiedData), '__temp_key__');
|
||||
// Then we need to apply our helper
|
||||
const cleanedData = cleanData(
|
||||
{ browserState: preparedData, serverState: initialData },
|
||||
{ browserState: modifiedData, serverState: initialData },
|
||||
currentContentTypeLayout,
|
||||
allLayoutData.components
|
||||
);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import get from 'lodash/get';
|
||||
import isArray from 'lodash/isArray';
|
||||
import isObject from 'lodash/isObject';
|
||||
import { getInitialDataPathUsingTempKeys } from '../../../utils/paths';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
@ -12,6 +13,8 @@ import isObject from 'lodash/isObject';
|
||||
* @returns
|
||||
*/
|
||||
const cleanData = ({ browserState, serverState }, currentSchema, componentsSchema) => {
|
||||
const rootServerState = serverState;
|
||||
const rootBrowserState = browserState;
|
||||
const getType = (schema, attrName) => get(schema, ['attributes', attrName, 'type'], '');
|
||||
const getOtherInfos = (schema, arr) => get(schema, ['attributes', ...arr], '');
|
||||
|
||||
@ -20,10 +23,12 @@ const cleanData = ({ browserState, serverState }, currentSchema, componentsSchem
|
||||
* @param {object} browserState – the modifiedData from REDUX
|
||||
* @param {object} serverState – the initialData from REDUX
|
||||
* @param {*} schema
|
||||
* @param {string} path
|
||||
* @returns
|
||||
*/
|
||||
const recursiveCleanData = (browserState, serverState, schema) => {
|
||||
const recursiveCleanData = (browserState, serverState, schema, pathToParent) => {
|
||||
return Object.keys(browserState).reduce((acc, current) => {
|
||||
const path = pathToParent ? `${pathToParent}.${current}` : current;
|
||||
const attrType = getType(schema, current);
|
||||
|
||||
// This is the field value
|
||||
@ -61,7 +66,8 @@ const cleanData = ({ browserState, serverState }, currentSchema, componentsSchem
|
||||
const subCleanedData = recursiveCleanData(
|
||||
data,
|
||||
(oldValue ?? [])[index],
|
||||
componentsSchema[component]
|
||||
componentsSchema[component],
|
||||
`${path}.${index}`
|
||||
);
|
||||
|
||||
return subCleanedData;
|
||||
@ -69,20 +75,25 @@ const cleanData = ({ browserState, serverState }, currentSchema, componentsSchem
|
||||
: value;
|
||||
} else {
|
||||
cleanedData = value
|
||||
? recursiveCleanData(value, oldValue, componentsSchema[component])
|
||||
? recursiveCleanData(value, oldValue, componentsSchema[component], path)
|
||||
: value;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'relation': {
|
||||
const trueInitialDataPath = getInitialDataPathUsingTempKeys(
|
||||
rootServerState,
|
||||
rootBrowserState
|
||||
)(path).join('.');
|
||||
|
||||
/**
|
||||
* Because of how repeatable components work when you dig into them the server
|
||||
* will have no object to compare too therefore no relation array will be setup
|
||||
* because the component has not been initialised, therefore we can safely assume
|
||||
* it needs to be added and provide a default empty array.
|
||||
*/
|
||||
let actualOldValue = oldValue ?? [];
|
||||
let actualOldValue = get(rootServerState, trueInitialDataPath, []);
|
||||
|
||||
const valuesWithPositions = value.map((relation, index, allRelations) => {
|
||||
const nextRelation = allRelations[index + 1];
|
||||
@ -141,7 +152,8 @@ const cleanData = ({ browserState, serverState }, currentSchema, componentsSchem
|
||||
const subCleanedData = recursiveCleanData(
|
||||
componentData,
|
||||
(oldValue ?? [])[index],
|
||||
componentsSchema[componentData.__component]
|
||||
componentsSchema[componentData.__component],
|
||||
`${path}.${index}`
|
||||
);
|
||||
|
||||
return subCleanedData;
|
||||
@ -157,7 +169,7 @@ const cleanData = ({ browserState, serverState }, currentSchema, componentsSchem
|
||||
}, {});
|
||||
};
|
||||
|
||||
return recursiveCleanData(browserState, serverState, currentSchema);
|
||||
return recursiveCleanData(browserState, serverState, currentSchema, '');
|
||||
};
|
||||
|
||||
// TODO: check which parts are still needed: I suspect the
|
||||
|
||||
@ -15,6 +15,7 @@ import { getTrad } from '../../utils';
|
||||
|
||||
import { PUBLICATION_STATES, RELATIONS_TO_DISPLAY, SEARCH_RESULTS_TO_DISPLAY } from './constants';
|
||||
import { connect, select, normalizeSearchResults, diffRelations, normalizeRelation } from './utils';
|
||||
import { getInitialDataPathUsingTempKeys } from '../../utils/paths';
|
||||
|
||||
export const RelationInputDataManager = ({
|
||||
error,
|
||||
@ -50,28 +51,7 @@ export const RelationInputDataManager = ({
|
||||
|
||||
const nameSplit = name.split('.');
|
||||
|
||||
const initialDataPath = nameSplit.reduce((acc, currentValue, index) => {
|
||||
const initialDataParent = get(initialData, acc);
|
||||
const modifiedDataTempKey = get(modifiedData, [
|
||||
...nameSplit.slice(0, index),
|
||||
currentValue,
|
||||
'__temp_key__',
|
||||
]);
|
||||
|
||||
if (Array.isArray(initialDataParent) && typeof modifiedDataTempKey === 'number') {
|
||||
const initialDataIndex = initialDataParent.findIndex(
|
||||
(entry) => entry.__temp_key__ === modifiedDataTempKey
|
||||
);
|
||||
|
||||
acc.push(initialDataIndex.toString());
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
acc.push(currentValue);
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
const initialDataPath = getInitialDataPathUsingTempKeys(initialData, modifiedData)(name);
|
||||
|
||||
const relationsFromModifiedData = get(modifiedData, name, []);
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ const getMaxTempKey = (arr) => {
|
||||
|
||||
const maxTempKey = Math.max.apply(
|
||||
Math,
|
||||
arr.map((o) => o.__temp_key__ ?? o.id)
|
||||
arr.map((o) => o.__temp_key__ ?? 0)
|
||||
);
|
||||
|
||||
return Number.isNaN(maxTempKey) ? -1 : maxTempKey;
|
||||
|
||||
37
packages/core/admin/admin/src/content-manager/utils/paths.js
Normal file
37
packages/core/admin/admin/src/content-manager/utils/paths.js
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* This file is for all helpers related to `paths` in the CM.
|
||||
*/
|
||||
import { get } from 'lodash';
|
||||
|
||||
/**
|
||||
* This is typically used in circumstances where there are re-orderable pieces e.g. Dynamic Zones
|
||||
* or Repeatable fields. It finds the _original_ location of the initial data using `__temp_key__` values
|
||||
* which are added to the fields in the `INIT_FORM` reducer to give array data a stable (when you add
|
||||
* a new item they wont have a server ID).
|
||||
*/
|
||||
export const getInitialDataPathUsingTempKeys = (initialData, modifiedData) => (currentPath) => {
|
||||
const splitPath = currentPath.split('.');
|
||||
|
||||
return splitPath.reduce((acc, currentValue, index) => {
|
||||
const initialDataParent = get(initialData, acc);
|
||||
const modifiedDataTempKey = get(modifiedData, [
|
||||
...splitPath.slice(0, index),
|
||||
currentValue,
|
||||
'__temp_key__',
|
||||
]);
|
||||
|
||||
if (Array.isArray(initialDataParent) && typeof modifiedDataTempKey === 'number') {
|
||||
const initialDataIndex = initialDataParent.findIndex(
|
||||
(entry) => entry.__temp_key__ === modifiedDataTempKey
|
||||
);
|
||||
|
||||
acc.push(initialDataIndex.toString());
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
acc.push(currentValue);
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user