diff --git a/packages/core/src/backend.ts b/packages/core/src/backend.ts index 181aa711..5f29fe1b 100644 --- a/packages/core/src/backend.ts +++ b/packages/core/src/backend.ts @@ -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'; diff --git a/packages/core/src/components/entry-editor/editor-control-pane/EditorControl.tsx b/packages/core/src/components/entry-editor/editor-control-pane/EditorControl.tsx index a616fc1d..4ffe4855 100644 --- a/packages/core/src/components/entry-editor/editor-control-pane/EditorControl.tsx +++ b/packages/core/src/components/entry-editor/editor-control-pane/EditorControl.tsx @@ -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, diff --git a/packages/core/src/lib/formatters.ts b/packages/core/src/lib/formatters.ts index 74603201..53e12505 100644 --- a/packages/core/src/lib/formatters.ts +++ b/packages/core/src/lib/formatters.ts @@ -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, diff --git a/packages/core/src/lib/i18n.ts b/packages/core/src/lib/i18n.ts index 6a243991..607ca2ca 100644 --- a/packages/core/src/lib/i18n.ts +++ b/packages/core/src/lib/i18n.ts @@ -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, diff --git a/packages/core/src/lib/util/__tests__/object.util.spec.ts b/packages/core/src/lib/util/__tests__/object.util.spec.ts deleted file mode 100644 index 4aba7e4f..00000000 --- a/packages/core/src/lib/util/__tests__/object.util.spec.ts +++ /dev/null @@ -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'); - }); - }); - }); -}); diff --git a/packages/core/src/lib/util/object.util.ts b/packages/core/src/lib/util/object.util.ts deleted file mode 100644 index 3d493e0f..00000000 --- a/packages/core/src/lib/util/object.util.ts +++ /dev/null @@ -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(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, - ); -} diff --git a/packages/core/src/reducers/entries.ts b/packages/core/src/reducers/entries.ts index c7035528..775896ae 100644 --- a/packages/core/src/reducers/entries.ts +++ b/packages/core/src/reducers/entries.ts @@ -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'; diff --git a/packages/core/src/reducers/entryDraft.ts b/packages/core/src/reducers/entryDraft.ts index bc6da642..8fa06eae 100644 --- a/packages/core/src/reducers/entryDraft.ts +++ b/packages/core/src/reducers/entryDraft.ts @@ -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), }; } diff --git a/packages/docs/content/releases.json b/packages/docs/content/releases.json index ce6aa55c..6ac4f205 100644 --- a/packages/docs/content/releases.json +++ b/packages/docs/content/releases.json @@ -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",