feat: update internal control value for list and object widget whenever store changes (#933)
This commit is contained in:
parent
1d4ae8ef18
commit
1ddcfbe153
@ -3,6 +3,7 @@ import attempt from 'lodash/attempt';
|
||||
import flatten from 'lodash/flatten';
|
||||
import get from 'lodash/get';
|
||||
import isError from 'lodash/isError';
|
||||
import set from 'lodash/set';
|
||||
import uniq from 'lodash/uniq';
|
||||
import { dirname } from 'path';
|
||||
|
||||
@ -45,7 +46,6 @@ import filterEntries from './lib/util/filter.util';
|
||||
import { DRAFT_MEDIA_FILES, selectMediaFilePublicPath } from './lib/util/media.util';
|
||||
import { selectCustomPath, slugFromCustomPath } from './lib/util/nested.util';
|
||||
import { isNullish } from './lib/util/null.util';
|
||||
import { set } from './lib/util/object.util';
|
||||
import { fileSearch, sortByScore } from './lib/util/search.util';
|
||||
import { dateParsers, expandPath, extractTemplateVars } from './lib/widgets/stringTemplate';
|
||||
import createEntry from './valueObjects/createEntry';
|
||||
|
@ -110,6 +110,15 @@ const EditorControl = ({
|
||||
);
|
||||
const hidden = useHidden(field, entry, listItemPath);
|
||||
|
||||
useEffect(() => {
|
||||
if (!['list', 'object'].includes(field.widget)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setInternalValue(finalStorageValue);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [finalStorageValue]);
|
||||
|
||||
useEffect(() => {
|
||||
if (hidden) {
|
||||
dispatch(changeDraftFieldValidation(path, [], i18n, isMeta));
|
||||
@ -220,10 +229,7 @@ const EditorControl = ({
|
||||
path,
|
||||
query,
|
||||
t,
|
||||
value:
|
||||
field.widget === 'list' || field.widget === 'object'
|
||||
? finalStorageValue
|
||||
: internalValue,
|
||||
value: internalValue,
|
||||
forList,
|
||||
listItemPath,
|
||||
forSingleList,
|
||||
|
@ -1,10 +1,10 @@
|
||||
import get from 'lodash/get';
|
||||
import set from 'lodash/set';
|
||||
|
||||
import { COMMIT_AUTHOR, COMMIT_DATE } from '../constants/commitProps';
|
||||
import { sanitizeSlug } from './urlHelper';
|
||||
import { selectIdentifier, selectInferredField } from './util/collection.util';
|
||||
import { selectField } from './util/field.util';
|
||||
import { set } from './util/object.util';
|
||||
import { isEmpty } from './util/string.util';
|
||||
import {
|
||||
addFileTemplateFields,
|
||||
|
@ -1,9 +1,9 @@
|
||||
import escapeRegExp from 'lodash/escapeRegExp';
|
||||
import get from 'lodash/get';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import set from 'lodash/set';
|
||||
|
||||
import { fileForEntry, selectEntrySlug } from './util/collection.util';
|
||||
import { set } from './util/object.util';
|
||||
|
||||
import type {
|
||||
BaseField,
|
||||
|
@ -1,159 +0,0 @@
|
||||
import { set } from '../object.util';
|
||||
|
||||
describe('object.util', () => {
|
||||
describe('set', () => {
|
||||
describe('simple object', () => {
|
||||
test('existing key', () => {
|
||||
const testObject = {
|
||||
something: '12345',
|
||||
somethingElse: 5,
|
||||
};
|
||||
|
||||
const updatedObject = set(testObject, 'something', '54321');
|
||||
|
||||
expect(testObject.something).toBe('12345');
|
||||
expect(updatedObject.something).toBe('54321');
|
||||
});
|
||||
|
||||
test('new key', () => {
|
||||
const testObject = {
|
||||
something: '12345',
|
||||
somethingElse: 5,
|
||||
} as {
|
||||
something: string;
|
||||
somethingElse: number;
|
||||
somethingNew?: string;
|
||||
};
|
||||
|
||||
const updatedObject = set(testObject, 'somethingNew', 'aNewValue');
|
||||
|
||||
expect(testObject.somethingNew).toBeUndefined();
|
||||
expect(updatedObject.somethingNew).toBe('aNewValue');
|
||||
});
|
||||
});
|
||||
|
||||
describe('nested object', () => {
|
||||
test('existing key', () => {
|
||||
const testObject = {
|
||||
something: '12345',
|
||||
somethingElse: {
|
||||
nestedValue: 65,
|
||||
},
|
||||
};
|
||||
|
||||
const updatedObject = set(testObject, 'somethingElse.nestedValue', 125);
|
||||
|
||||
expect(testObject.somethingElse.nestedValue).toBe(65);
|
||||
expect(updatedObject.somethingElse.nestedValue).toBe(125);
|
||||
});
|
||||
|
||||
test('new key', () => {
|
||||
const testObject = {
|
||||
something: '12345',
|
||||
somethingElse: {
|
||||
nestedValue: 65,
|
||||
},
|
||||
} as {
|
||||
something: string;
|
||||
somethingElse: {
|
||||
nestedValue: number;
|
||||
};
|
||||
somethingNew?: {
|
||||
nestedLayer: {
|
||||
anotherNestedLayer: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
const updatedObject = set(
|
||||
testObject,
|
||||
'somethingNew.nestedLayer.anotherNestedLayer',
|
||||
'aNewNestedValue',
|
||||
);
|
||||
|
||||
expect(testObject.somethingNew?.nestedLayer.anotherNestedLayer).toBeUndefined();
|
||||
expect(updatedObject.somethingNew?.nestedLayer.anotherNestedLayer).toBe('aNewNestedValue');
|
||||
});
|
||||
});
|
||||
|
||||
describe('simple array', () => {
|
||||
test('existing key', () => {
|
||||
const testObject = {
|
||||
something: '12345',
|
||||
somethingElse: [6, 5, 3],
|
||||
};
|
||||
|
||||
const updatedObject = set(testObject, 'somethingElse.1', 13);
|
||||
|
||||
expect(updatedObject.somethingElse).toStrictEqual([6, 13, 3]);
|
||||
});
|
||||
|
||||
test('new index should be ignored', () => {
|
||||
const testObject = {
|
||||
something: '12345',
|
||||
somethingElse: [6, 5, 3],
|
||||
};
|
||||
|
||||
const updatedObject = set(testObject, 'somethingElse.3', 84);
|
||||
|
||||
expect(updatedObject.somethingElse).toStrictEqual([6, 5, 3]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('object array', () => {
|
||||
test('existing key', () => {
|
||||
const testObject = {
|
||||
something: '12345',
|
||||
somethingElse: [
|
||||
{ name: 'one', value: '11111' },
|
||||
{ name: 'two', value: '22222' },
|
||||
{ name: 'three', value: '33333' },
|
||||
],
|
||||
};
|
||||
|
||||
const updatedObject = set(testObject, 'somethingElse.1.value', 'aNewValue');
|
||||
|
||||
expect(testObject.somethingElse[1].value).toBe('22222');
|
||||
expect(updatedObject.somethingElse[1].value).toBe('aNewValue');
|
||||
});
|
||||
|
||||
test('new index should be ignored', () => {
|
||||
const testObject = {
|
||||
something: '12345',
|
||||
somethingElse: [
|
||||
{ name: 'one', value: '11111' },
|
||||
{ name: 'two', value: '22222' },
|
||||
{ name: 'three', value: '33333' },
|
||||
],
|
||||
};
|
||||
|
||||
const updatedObject = set(testObject, 'somethingElse.3.value', 'valueToBeIgnored');
|
||||
|
||||
expect(updatedObject.somethingElse.length).toBe(3);
|
||||
});
|
||||
|
||||
test('new key inside existing index', () => {
|
||||
const testObject = {
|
||||
something: '12345',
|
||||
somethingElse: [
|
||||
{ name: 'one', value: '11111' },
|
||||
{ name: 'two', value: '22222' },
|
||||
{ name: 'three', value: '33333' },
|
||||
],
|
||||
} as {
|
||||
something: string;
|
||||
somethingElse: {
|
||||
name: string;
|
||||
value: string;
|
||||
newKey?: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
const updatedObject = set(testObject, 'somethingElse.1.newKey', 'newValueToBeAdded');
|
||||
|
||||
expect(testObject.somethingElse[1].newKey).toBeUndefined();
|
||||
expect(updatedObject.somethingElse[1].newKey).toBe('newValueToBeAdded');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,45 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
function setIn(target: any, path: (string | number)[], value: unknown): any {
|
||||
if (path.length === 0) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const pathSegment = path[0];
|
||||
const restOfPath = path.slice(1);
|
||||
|
||||
if (Array.isArray(target)) {
|
||||
const localTarget = [...(target ?? [])];
|
||||
if (Number.isNaN(+pathSegment)) {
|
||||
return localTarget;
|
||||
}
|
||||
|
||||
const index = +pathSegment;
|
||||
if (index < 0 || index >= localTarget.length) {
|
||||
return localTarget;
|
||||
}
|
||||
|
||||
localTarget[index] = setIn(localTarget[index], restOfPath, value);
|
||||
return localTarget;
|
||||
}
|
||||
|
||||
const localTarget = target ?? {};
|
||||
return {
|
||||
...localTarget,
|
||||
[pathSegment]: setIn(localTarget[pathSegment], restOfPath, value),
|
||||
};
|
||||
}
|
||||
|
||||
export function set<T>(target: T, path: string | undefined | null, value: unknown): T;
|
||||
export function set(target: any, path: string | undefined | null, value: unknown): any {
|
||||
return setIn(
|
||||
target,
|
||||
(path ?? '').split('.').map(part => {
|
||||
if (Number.isNaN(+part)) {
|
||||
return part;
|
||||
}
|
||||
|
||||
return +part;
|
||||
}),
|
||||
value,
|
||||
);
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import once from 'lodash/once';
|
||||
import set from 'lodash/set';
|
||||
import sortBy from 'lodash/sortBy';
|
||||
|
||||
import {
|
||||
@ -23,7 +24,6 @@ import {
|
||||
SORT_ENTRIES_SUCCESS,
|
||||
} from '../constants';
|
||||
import { VIEW_STYLES, VIEW_STYLE_TABLE } from '../constants/views';
|
||||
import { set } from '../lib/util/object.util';
|
||||
|
||||
import type { EntriesAction } from '../actions/entries';
|
||||
import type { SearchAction } from '../actions/search';
|
||||
|
@ -1,4 +1,6 @@
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import set from 'lodash/set';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import {
|
||||
@ -23,7 +25,6 @@ import {
|
||||
import { duplicateI18nFields, getDataPath } from '../lib/i18n';
|
||||
import { fileForEntry } from '../lib/util/collection.util';
|
||||
import { applyDefaultsToDraftData } from '../lib/util/entry.util';
|
||||
import { set } from '../lib/util/object.util';
|
||||
|
||||
import type { EntriesAction } from '../actions/entries';
|
||||
import type { Entry, FieldsErrors } from '../interface';
|
||||
@ -70,7 +71,7 @@ function entryDraftReducer(
|
||||
...entry,
|
||||
data: applyDefaultsToDraftData(fields, undefined, entry.data),
|
||||
},
|
||||
original: entry,
|
||||
original: cloneDeep(entry),
|
||||
fieldsErrors: {},
|
||||
hasChanged: false,
|
||||
key: uuid(),
|
||||
@ -89,7 +90,7 @@ function entryDraftReducer(
|
||||
return {
|
||||
...newState,
|
||||
entry,
|
||||
original: entry,
|
||||
original: cloneDeep(entry),
|
||||
fieldsErrors: {},
|
||||
hasChanged: false,
|
||||
key: uuid(),
|
||||
@ -115,7 +116,7 @@ function entryDraftReducer(
|
||||
return {
|
||||
...state,
|
||||
entry,
|
||||
original: entry,
|
||||
original: cloneDeep(entry),
|
||||
fieldsErrors: {},
|
||||
hasChanged: true,
|
||||
key: uuid(),
|
||||
@ -135,7 +136,7 @@ function entryDraftReducer(
|
||||
return {
|
||||
...newState,
|
||||
entry,
|
||||
original: entry,
|
||||
original: cloneDeep(entry),
|
||||
fieldsErrors: {},
|
||||
hasChanged: true,
|
||||
};
|
||||
@ -203,9 +204,11 @@ function entryDraftReducer(
|
||||
? ['meta']
|
||||
: (i18n && getDataPath(i18n.currentLocale, i18n.defaultLocale)) || ['data'];
|
||||
|
||||
const newEntry = cloneDeep(newState.entry);
|
||||
|
||||
newState = {
|
||||
...newState,
|
||||
entry: set(newState.entry, `${dataPath.join('.')}.${path}`, value),
|
||||
entry: set(newEntry, `${dataPath.join('.')}.${path}`, value),
|
||||
};
|
||||
|
||||
if (i18n) {
|
||||
@ -213,14 +216,14 @@ function entryDraftReducer(
|
||||
}
|
||||
|
||||
let hasChanged =
|
||||
!isEqual(newState.entry?.meta, newState.original?.meta) ||
|
||||
!isEqual(newState.entry?.data, newState.original?.data);
|
||||
!isEqual(newEntry?.meta, newState.original?.meta) ||
|
||||
!isEqual(newEntry?.data, newState.original?.data);
|
||||
|
||||
const i18nData = newState.entry?.i18n ?? {};
|
||||
const i18nData = newEntry?.i18n ?? {};
|
||||
for (const locale in i18nData) {
|
||||
hasChanged =
|
||||
hasChanged ||
|
||||
!isEqual(newState.entry?.i18n?.[locale]?.data, newState.original?.i18n?.[locale]?.data);
|
||||
!isEqual(newEntry?.i18n?.[locale]?.data, newState.original?.i18n?.[locale]?.data);
|
||||
}
|
||||
|
||||
return {
|
||||
@ -322,7 +325,7 @@ function entryDraftReducer(
|
||||
...newState,
|
||||
hasChanged: false,
|
||||
entry,
|
||||
original: entry,
|
||||
original: cloneDeep(entry),
|
||||
};
|
||||
}
|
||||
|
||||
@ -343,7 +346,7 @@ function entryDraftReducer(
|
||||
...newState,
|
||||
hasChanged: false,
|
||||
entry,
|
||||
original: entry,
|
||||
original: cloneDeep(entry),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,25 @@
|
||||
{
|
||||
"releases": [
|
||||
{
|
||||
"date": "2023-10-10T10:00:00.000Z",
|
||||
"version": "v3.3.7",
|
||||
"type": "patch"
|
||||
},
|
||||
{
|
||||
"date": "2023-10-06T10:00:00.000Z",
|
||||
"version": "v3.3.6",
|
||||
"type": "patch"
|
||||
},
|
||||
{
|
||||
"date": "2023-10-05T10:00:00.000Z",
|
||||
"version": "v3.3.5",
|
||||
"type": "patch"
|
||||
},
|
||||
{
|
||||
"date": "2023-10-04T10:00:00.000Z",
|
||||
"version": "v3.3.4",
|
||||
"type": "patch"
|
||||
},
|
||||
{
|
||||
"date": "2023-09-24T10:00:00.000Z",
|
||||
"version": "v3.3.3",
|
||||
|
Loading…
x
Reference in New Issue
Block a user