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 flatten from 'lodash/flatten';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import isError from 'lodash/isError';
|
import isError from 'lodash/isError';
|
||||||
|
import set from 'lodash/set';
|
||||||
import uniq from 'lodash/uniq';
|
import uniq from 'lodash/uniq';
|
||||||
import { dirname } from 'path';
|
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 { DRAFT_MEDIA_FILES, selectMediaFilePublicPath } from './lib/util/media.util';
|
||||||
import { selectCustomPath, slugFromCustomPath } from './lib/util/nested.util';
|
import { selectCustomPath, slugFromCustomPath } from './lib/util/nested.util';
|
||||||
import { isNullish } from './lib/util/null.util';
|
import { isNullish } from './lib/util/null.util';
|
||||||
import { set } from './lib/util/object.util';
|
|
||||||
import { fileSearch, sortByScore } from './lib/util/search.util';
|
import { fileSearch, sortByScore } from './lib/util/search.util';
|
||||||
import { dateParsers, expandPath, extractTemplateVars } from './lib/widgets/stringTemplate';
|
import { dateParsers, expandPath, extractTemplateVars } from './lib/widgets/stringTemplate';
|
||||||
import createEntry from './valueObjects/createEntry';
|
import createEntry from './valueObjects/createEntry';
|
||||||
|
@ -110,6 +110,15 @@ const EditorControl = ({
|
|||||||
);
|
);
|
||||||
const hidden = useHidden(field, entry, listItemPath);
|
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(() => {
|
useEffect(() => {
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
dispatch(changeDraftFieldValidation(path, [], i18n, isMeta));
|
dispatch(changeDraftFieldValidation(path, [], i18n, isMeta));
|
||||||
@ -220,10 +229,7 @@ const EditorControl = ({
|
|||||||
path,
|
path,
|
||||||
query,
|
query,
|
||||||
t,
|
t,
|
||||||
value:
|
value: internalValue,
|
||||||
field.widget === 'list' || field.widget === 'object'
|
|
||||||
? finalStorageValue
|
|
||||||
: internalValue,
|
|
||||||
forList,
|
forList,
|
||||||
listItemPath,
|
listItemPath,
|
||||||
forSingleList,
|
forSingleList,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
|
import set from 'lodash/set';
|
||||||
|
|
||||||
import { COMMIT_AUTHOR, COMMIT_DATE } from '../constants/commitProps';
|
import { COMMIT_AUTHOR, COMMIT_DATE } from '../constants/commitProps';
|
||||||
import { sanitizeSlug } from './urlHelper';
|
import { sanitizeSlug } from './urlHelper';
|
||||||
import { selectIdentifier, selectInferredField } from './util/collection.util';
|
import { selectIdentifier, selectInferredField } from './util/collection.util';
|
||||||
import { selectField } from './util/field.util';
|
import { selectField } from './util/field.util';
|
||||||
import { set } from './util/object.util';
|
|
||||||
import { isEmpty } from './util/string.util';
|
import { isEmpty } from './util/string.util';
|
||||||
import {
|
import {
|
||||||
addFileTemplateFields,
|
addFileTemplateFields,
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import escapeRegExp from 'lodash/escapeRegExp';
|
import escapeRegExp from 'lodash/escapeRegExp';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import groupBy from 'lodash/groupBy';
|
import groupBy from 'lodash/groupBy';
|
||||||
|
import set from 'lodash/set';
|
||||||
|
|
||||||
import { fileForEntry, selectEntrySlug } from './util/collection.util';
|
import { fileForEntry, selectEntrySlug } from './util/collection.util';
|
||||||
import { set } from './util/object.util';
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
BaseField,
|
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 once from 'lodash/once';
|
||||||
|
import set from 'lodash/set';
|
||||||
import sortBy from 'lodash/sortBy';
|
import sortBy from 'lodash/sortBy';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -23,7 +24,6 @@ import {
|
|||||||
SORT_ENTRIES_SUCCESS,
|
SORT_ENTRIES_SUCCESS,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
import { VIEW_STYLES, VIEW_STYLE_TABLE } from '../constants/views';
|
import { VIEW_STYLES, VIEW_STYLE_TABLE } from '../constants/views';
|
||||||
import { set } from '../lib/util/object.util';
|
|
||||||
|
|
||||||
import type { EntriesAction } from '../actions/entries';
|
import type { EntriesAction } from '../actions/entries';
|
||||||
import type { SearchAction } from '../actions/search';
|
import type { SearchAction } from '../actions/search';
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
|
import set from 'lodash/set';
|
||||||
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -23,7 +25,6 @@ import {
|
|||||||
import { duplicateI18nFields, getDataPath } from '../lib/i18n';
|
import { duplicateI18nFields, getDataPath } from '../lib/i18n';
|
||||||
import { fileForEntry } from '../lib/util/collection.util';
|
import { fileForEntry } from '../lib/util/collection.util';
|
||||||
import { applyDefaultsToDraftData } from '../lib/util/entry.util';
|
import { applyDefaultsToDraftData } from '../lib/util/entry.util';
|
||||||
import { set } from '../lib/util/object.util';
|
|
||||||
|
|
||||||
import type { EntriesAction } from '../actions/entries';
|
import type { EntriesAction } from '../actions/entries';
|
||||||
import type { Entry, FieldsErrors } from '../interface';
|
import type { Entry, FieldsErrors } from '../interface';
|
||||||
@ -70,7 +71,7 @@ function entryDraftReducer(
|
|||||||
...entry,
|
...entry,
|
||||||
data: applyDefaultsToDraftData(fields, undefined, entry.data),
|
data: applyDefaultsToDraftData(fields, undefined, entry.data),
|
||||||
},
|
},
|
||||||
original: entry,
|
original: cloneDeep(entry),
|
||||||
fieldsErrors: {},
|
fieldsErrors: {},
|
||||||
hasChanged: false,
|
hasChanged: false,
|
||||||
key: uuid(),
|
key: uuid(),
|
||||||
@ -89,7 +90,7 @@ function entryDraftReducer(
|
|||||||
return {
|
return {
|
||||||
...newState,
|
...newState,
|
||||||
entry,
|
entry,
|
||||||
original: entry,
|
original: cloneDeep(entry),
|
||||||
fieldsErrors: {},
|
fieldsErrors: {},
|
||||||
hasChanged: false,
|
hasChanged: false,
|
||||||
key: uuid(),
|
key: uuid(),
|
||||||
@ -115,7 +116,7 @@ function entryDraftReducer(
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
entry,
|
entry,
|
||||||
original: entry,
|
original: cloneDeep(entry),
|
||||||
fieldsErrors: {},
|
fieldsErrors: {},
|
||||||
hasChanged: true,
|
hasChanged: true,
|
||||||
key: uuid(),
|
key: uuid(),
|
||||||
@ -135,7 +136,7 @@ function entryDraftReducer(
|
|||||||
return {
|
return {
|
||||||
...newState,
|
...newState,
|
||||||
entry,
|
entry,
|
||||||
original: entry,
|
original: cloneDeep(entry),
|
||||||
fieldsErrors: {},
|
fieldsErrors: {},
|
||||||
hasChanged: true,
|
hasChanged: true,
|
||||||
};
|
};
|
||||||
@ -203,9 +204,11 @@ function entryDraftReducer(
|
|||||||
? ['meta']
|
? ['meta']
|
||||||
: (i18n && getDataPath(i18n.currentLocale, i18n.defaultLocale)) || ['data'];
|
: (i18n && getDataPath(i18n.currentLocale, i18n.defaultLocale)) || ['data'];
|
||||||
|
|
||||||
|
const newEntry = cloneDeep(newState.entry);
|
||||||
|
|
||||||
newState = {
|
newState = {
|
||||||
...newState,
|
...newState,
|
||||||
entry: set(newState.entry, `${dataPath.join('.')}.${path}`, value),
|
entry: set(newEntry, `${dataPath.join('.')}.${path}`, value),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (i18n) {
|
if (i18n) {
|
||||||
@ -213,14 +216,14 @@ function entryDraftReducer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let hasChanged =
|
let hasChanged =
|
||||||
!isEqual(newState.entry?.meta, newState.original?.meta) ||
|
!isEqual(newEntry?.meta, newState.original?.meta) ||
|
||||||
!isEqual(newState.entry?.data, newState.original?.data);
|
!isEqual(newEntry?.data, newState.original?.data);
|
||||||
|
|
||||||
const i18nData = newState.entry?.i18n ?? {};
|
const i18nData = newEntry?.i18n ?? {};
|
||||||
for (const locale in i18nData) {
|
for (const locale in i18nData) {
|
||||||
hasChanged =
|
hasChanged =
|
||||||
hasChanged ||
|
hasChanged ||
|
||||||
!isEqual(newState.entry?.i18n?.[locale]?.data, newState.original?.i18n?.[locale]?.data);
|
!isEqual(newEntry?.i18n?.[locale]?.data, newState.original?.i18n?.[locale]?.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -322,7 +325,7 @@ function entryDraftReducer(
|
|||||||
...newState,
|
...newState,
|
||||||
hasChanged: false,
|
hasChanged: false,
|
||||||
entry,
|
entry,
|
||||||
original: entry,
|
original: cloneDeep(entry),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,7 +346,7 @@ function entryDraftReducer(
|
|||||||
...newState,
|
...newState,
|
||||||
hasChanged: false,
|
hasChanged: false,
|
||||||
entry,
|
entry,
|
||||||
original: entry,
|
original: cloneDeep(entry),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,25 @@
|
|||||||
{
|
{
|
||||||
"releases": [
|
"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",
|
"date": "2023-09-24T10:00:00.000Z",
|
||||||
"version": "v3.3.3",
|
"version": "v3.3.3",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user